001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools.deploy;
016    
017    import com.liferay.portal.kernel.plugin.PluginPackage;
018    import com.liferay.portal.kernel.util.FileUtil;
019    import com.liferay.portal.kernel.util.PropsKeys;
020    import com.liferay.portal.kernel.util.ServerDetector;
021    import com.liferay.portal.kernel.util.StringBundler;
022    import com.liferay.portal.kernel.util.StringUtil;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.kernel.xml.Document;
025    import com.liferay.portal.kernel.xml.Element;
026    import com.liferay.portal.kernel.xml.SAXReaderUtil;
027    import com.liferay.portal.model.Plugin;
028    import com.liferay.portal.util.InitUtil;
029    import com.liferay.portal.util.Portal;
030    import com.liferay.portal.util.PortalUtil;
031    import com.liferay.portal.util.PrefsPropsUtil;
032    import com.liferay.portal.util.PropsValues;
033    import com.liferay.portal.xml.DocumentImpl;
034    import com.liferay.util.TextFormatter;
035    import com.liferay.util.bridges.mvc.MVCPortlet;
036    import com.liferay.util.xml.XMLMerger;
037    import com.liferay.util.xml.descriptor.FacesXMLDescriptor;
038    
039    import java.io.File;
040    
041    import java.util.ArrayList;
042    import java.util.HashMap;
043    import java.util.Iterator;
044    import java.util.List;
045    import java.util.Map;
046    import java.util.Properties;
047    
048    /**
049     * @author Brian Wing Shun Chan
050     * @author Brian Myunghun Kim
051     */
052    public class PortletDeployer extends BaseDeployer {
053    
054            public static final String JSF_MYFACES =
055                    "org.apache.myfaces.portlet.MyFacesGenericPortlet";
056    
057            public static final String JSF_STANDARD =
058                    "javax.portlet.faces.GenericFacesPortlet";
059    
060            public static final String JSF_SUN =
061                    "com.sun.faces.portlet.FacesPortlet";
062    
063            public static final String LIFERAY_RENDER_KIT_FACTORY =
064                    "com.liferay.util.jsf.sun.faces.renderkit.LiferayRenderKitFactoryImpl";
065    
066            public static final String MYFACES_CONTEXT_FACTORY =
067                    "com.liferay.util.bridges.jsf.myfaces.MyFacesContextFactoryImpl";
068    
069            public static void main(String[] args) {
070                    InitUtil.initWithSpring();
071    
072                    List<String> wars = new ArrayList<String>();
073                    List<String> jars = new ArrayList<String>();
074    
075                    for (String arg : args) {
076                            if (arg.endsWith(".war")) {
077                                    wars.add(arg);
078                            }
079                            else if (arg.endsWith(".jar")) {
080                                    jars.add(arg);
081                            }
082                    }
083    
084                    new PortletDeployer(wars, jars);
085            }
086    
087            protected PortletDeployer() {
088            }
089    
090            protected PortletDeployer(List<String> wars, List<String> jars) {
091                    super(wars, jars);
092            }
093    
094            protected void checkArguments() {
095                    super.checkArguments();
096    
097                    if (Validator.isNull(portletTaglibDTD)) {
098                            throw new IllegalArgumentException(
099                                    "The system property deployer.portlet.taglib.dtd is not set");
100                    }
101            }
102    
103            protected void copyXmls(
104                            File srcFile, String displayName, PluginPackage pluginPackage)
105                    throws Exception {
106    
107                    super.copyXmls(srcFile, displayName, pluginPackage);
108    
109                    if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
110                            copyDependencyXml("context.xml", srcFile + "/META-INF");
111                    }
112            }
113    
114            protected String getExtraContent(
115                            double webXmlVersion, File srcFile, String displayName)
116                    throws Exception {
117    
118                    StringBundler sb = new StringBundler();
119    
120                    String extraContent = super.getExtraContent(
121                            webXmlVersion, srcFile, displayName);
122    
123                    sb.append(extraContent);
124    
125                    if (ServerDetector.isWebSphere()) {
126                            sb.append("<context-param>");
127                            sb.append("<param-name>");
128                            sb.append("com.ibm.websphere.portletcontainer.");
129                            sb.append("PortletDeploymentEnabled");
130                            sb.append("</param-name>");
131                            sb.append("<param-value>false</param-value>");
132                            sb.append("</context-param>");
133                    }
134    
135                    File facesXML = new File(srcFile + "/WEB-INF/faces-config.xml");
136                    File portletXML = new File(
137                            srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD);
138                    File webXML = new File(srcFile + "/WEB-INF/web.xml");
139    
140                    updatePortletXML(portletXML);
141    
142                    sb.append(getServletContent(portletXML, webXML));
143    
144                    setupJSF(facesXML, portletXML);
145    
146                    if (_sunFacesPortlet) {
147    
148                            // LiferayConfigureListener
149    
150                            sb.append("<listener>");
151                            sb.append("<listener-class>");
152                            sb.append("com.liferay.util.bridges.jsf.sun.");
153                            sb.append("LiferayConfigureListener");
154                            sb.append("</listener-class>");
155                            sb.append("</listener>");
156                    }
157    
158                    // PortletContextListener
159    
160                    sb.append("<listener>");
161                    sb.append("<listener-class>");
162                    sb.append("com.liferay.portal.kernel.servlet.PortletContextListener");
163                    sb.append("</listener-class>");
164                    sb.append("</listener>");
165    
166                    // Speed filters
167    
168                    sb.append(getSpeedFiltersContent(srcFile));
169    
170                    return sb.toString();
171            }
172    
173            protected String getServletContent(File portletXML, File webXML)
174                    throws Exception {
175    
176                    StringBundler sb = new StringBundler();
177    
178                    // Add wrappers for portlets
179    
180                    Document doc = SAXReaderUtil.read(portletXML);
181    
182                    Element root = doc.getRootElement();
183    
184                    Iterator<Element> itr1 = root.elements("portlet").iterator();
185    
186                    while (itr1.hasNext()) {
187                            Element portlet = itr1.next();
188    
189                            String portletName = PortalUtil.getJsSafePortletId(
190                                    portlet.elementText("portlet-name"));
191                            String portletClass = portlet.elementText("portlet-class");
192    
193                            sb.append("<servlet>");
194                            sb.append("<servlet-name>");
195                            sb.append(portletName);
196                            sb.append("</servlet-name>");
197                            sb.append("<servlet-class>");
198                            sb.append("com.liferay.portal.kernel.servlet.PortletServlet");
199                            sb.append("</servlet-class>");
200                            sb.append("<init-param>");
201                            sb.append("<param-name>portlet-class</param-name>");
202                            sb.append("<param-value>");
203                            sb.append(portletClass);
204                            sb.append("</param-value>");
205                            sb.append("</init-param>");
206                            sb.append("<load-on-startup>0</load-on-startup>");
207                            sb.append("</servlet>");
208    
209                            sb.append("<servlet-mapping>");
210                            sb.append("<servlet-name>");
211                            sb.append(portletName);
212                            sb.append("</servlet-name>");
213                            sb.append("<url-pattern>/");
214                            sb.append(portletName);
215                            sb.append("/*</url-pattern>");
216                            sb.append("</servlet-mapping>");
217                    }
218    
219                    // Make sure there is a company id specified
220    
221                    doc = SAXReaderUtil.read(webXML);
222    
223                    root = doc.getRootElement();
224    
225                    // Remove deprecated references to SharedServletWrapper
226    
227                    itr1 = root.elements("servlet").iterator();
228    
229                    while (itr1.hasNext()) {
230                            Element servlet = itr1.next();
231    
232                            String icon = servlet.elementText("icon");
233                            String servletName = servlet.elementText("servlet-name");
234                            String displayName = servlet.elementText("display-name");
235                            String description = servlet.elementText("description");
236                            String servletClass = servlet.elementText("servlet-class");
237                            List<Element> initParams = servlet.elements("init-param");
238                            String loadOnStartup = servlet.elementText("load-on-startup");
239                            String runAs = servlet.elementText("run-as");
240                            List<Element> securityRoleRefs = servlet.elements(
241                                    "security-role-ref");
242    
243                            if ((servletClass != null) &&
244                                    (servletClass.equals(
245                                            "com.liferay.portal.servlet.SharedServletWrapper"))) {
246    
247                                    sb.append("<servlet>");
248    
249                                    if (icon != null) {
250                                            sb.append("<icon>");
251                                            sb.append(icon);
252                                            sb.append("</icon>");
253                                    }
254    
255                                    if (servletName != null) {
256                                            sb.append("<servlet-name>");
257                                            sb.append(servletName);
258                                            sb.append("</servlet-name>");
259                                    }
260    
261                                    if (displayName != null) {
262                                            sb.append("<display-name>");
263                                            sb.append(displayName);
264                                            sb.append("</display-name>");
265                                    }
266    
267                                    if (description != null) {
268                                            sb.append("<description>");
269                                            sb.append(description);
270                                            sb.append("</description>");
271                                    }
272    
273                                    Iterator<Element> itr2 = initParams.iterator();
274    
275                                    while (itr2.hasNext()) {
276                                            Element initParam = itr2.next();
277    
278                                            String paramName = initParam.elementText("param-name");
279                                            String paramValue = initParam.elementText("param-value");
280    
281                                            if ((paramName != null) &&
282                                                    (paramName.equals("servlet-class"))) {
283    
284                                                    sb.append("<servlet-class>");
285                                                    sb.append(paramValue);
286                                                    sb.append("</servlet-class>");
287                                            }
288                                    }
289    
290                                    itr2 = initParams.iterator();
291    
292                                    while (itr2.hasNext()) {
293                                            Element initParam = itr2.next();
294    
295                                            String paramName = initParam.elementText("param-name");
296                                            String paramValue = initParam.elementText("param-value");
297                                            String paramDesc = initParam.elementText("description");
298    
299                                            if ((paramName != null) &&
300                                                    (!paramName.equals("servlet-class"))) {
301    
302                                                    sb.append("<init-param>");
303                                                    sb.append("<param-name>");
304                                                    sb.append(paramName);
305                                                    sb.append("</param-name>");
306    
307                                                    if (paramValue != null) {
308                                                            sb.append("<param-value>");
309                                                            sb.append(paramValue);
310                                                            sb.append("</param-value>");
311                                                    }
312    
313                                                    if (paramDesc != null) {
314                                                            sb.append("<description>");
315                                                            sb.append(paramDesc);
316                                                            sb.append("</description>");
317                                                    }
318    
319                                                    sb.append("</init-param>");
320                                            }
321                                    }
322    
323                                    if (loadOnStartup != null) {
324                                            sb.append("<load-on-startup>");
325                                            sb.append(loadOnStartup);
326                                            sb.append("</load-on-startup>");
327                                    }
328    
329                                    if (runAs != null) {
330                                            sb.append("<run-as>");
331                                            sb.append(runAs);
332                                            sb.append("</run-as>");
333                                    }
334    
335                                    itr2 = securityRoleRefs.iterator();
336    
337                                    while (itr2.hasNext()) {
338                                            Element roleRef = itr2.next();
339    
340                                            String roleDesc = roleRef.elementText("description");
341                                            String roleName = roleRef.elementText("role-name");
342                                            String roleLink = roleRef.elementText("role-link");
343    
344                                            sb.append("<security-role-ref>");
345    
346                                            if (roleDesc != null) {
347                                                    sb.append("<description>");
348                                                    sb.append(roleDesc);
349                                                    sb.append("</description>");
350                                            }
351    
352                                            if (roleName != null) {
353                                                    sb.append("<role-name>");
354                                                    sb.append(roleName);
355                                                    sb.append("</role-name>");
356                                            }
357    
358                                            if (roleLink != null) {
359                                                    sb.append("<role-link>");
360                                                    sb.append(roleLink);
361                                                    sb.append("</role-link>");
362                                            }
363    
364                                            sb.append("</security-role-ref>");
365                                    }
366    
367                                    sb.append("</servlet>");
368                            }
369                    }
370    
371                    return sb.toString();
372            }
373    
374            protected void processPluginPackageProperties(
375                            File srcFile, String displayName, PluginPackage pluginPackage)
376                    throws Exception {
377    
378                    if (pluginPackage == null) {
379                            return;
380                    }
381    
382                    Properties properties = getPluginPackageProperties(srcFile);
383    
384                    if ((properties == null) || (properties.size() == 0)) {
385                            return;
386                    }
387    
388                    String moduleGroupId = pluginPackage.getGroupId();
389                    String moduleArtifactId = pluginPackage.getArtifactId();
390                    String moduleVersion = pluginPackage.getVersion();
391    
392                    String pluginName = pluginPackage.getName();
393                    String pluginType = pluginPackage.getTypes().get(0);
394                    String pluginTypeName = TextFormatter.format(
395                            pluginType, TextFormatter.J);
396    
397                    if (!pluginType.equals(Plugin.TYPE_PORTLET)) {
398                            return;
399                    }
400    
401                    String tags = getPluginPackageTagsXml(pluginPackage.getTags());
402                    String shortDescription = pluginPackage.getShortDescription();
403                    String longDescription = pluginPackage.getLongDescription();
404                    String changeLog = pluginPackage.getChangeLog();
405                    String pageURL = pluginPackage.getPageURL();
406                    String author = pluginPackage.getAuthor();
407                    String licenses = getPluginPackageLicensesXml(
408                            pluginPackage.getLicenses());
409                    String liferayVersions = getPluginPackageLiferayVersionsXml(
410                            pluginPackage.getLiferayVersions());
411    
412                    Map<String, String> filterMap = new HashMap<String, String>();
413    
414                    filterMap.put("module_group_id", moduleGroupId);
415                    filterMap.put("module_artifact_id", moduleArtifactId);
416                    filterMap.put("module_version", moduleVersion);
417    
418                    filterMap.put("plugin_name", pluginName);
419                    filterMap.put("plugin_type", pluginType);
420                    filterMap.put("plugin_type_name", pluginTypeName);
421    
422                    filterMap.put("tags", tags);
423                    filterMap.put("short_description", shortDescription);
424                    filterMap.put("long_description", longDescription);
425                    filterMap.put("change_log", changeLog);
426                    filterMap.put("page_url", pageURL);
427                    filterMap.put("author", author);
428                    filterMap.put("licenses", licenses);
429                    filterMap.put("liferay_versions", liferayVersions);
430    
431                    copyDependencyXml(
432                            "liferay-plugin-package.xml", srcFile + "/WEB-INF", filterMap,
433                            true);
434            }
435    
436            protected void setupJSF(File facesXML, File portletXML) throws Exception {
437                    _myFacesPortlet = false;
438                    _sunFacesPortlet = false;
439    
440                    if (!facesXML.exists()) {
441                            return;
442                    }
443    
444                    // portlet.xml
445    
446                    Document doc = SAXReaderUtil.read(portletXML, true);
447    
448                    Element root = doc.getRootElement();
449    
450                    List<Element> elements = root.elements("portlet");
451    
452                    Iterator<Element> itr = elements.iterator();
453    
454                    while (itr.hasNext()) {
455                            Element portlet = itr.next();
456    
457                            String portletClass = portlet.elementText("portlet-class");
458    
459                            if (portletClass.equals(JSF_MYFACES)) {
460                                    _myFacesPortlet = true;
461    
462                                    break;
463                            }
464                            else if (portletClass.equals(JSF_SUN)) {
465                                    _sunFacesPortlet = true;
466    
467                                    break;
468                            }
469                    }
470    
471                    // faces-config.xml
472    
473                    doc = SAXReaderUtil.read(facesXML, true);
474    
475                    root = doc.getRootElement();
476    
477                    Element factoryEl = root.element("factory");
478    
479                    Element renderKitFactoryEl = null;
480                    Element facesContextFactoryEl = null;
481    
482                    if (factoryEl == null) {
483                            factoryEl = root.addElement("factory");
484                    }
485    
486                    renderKitFactoryEl = factoryEl.element("render-kit-factory");
487                    facesContextFactoryEl = factoryEl.element("faces-context-factory");
488    
489                    if ((appServerType.equals("orion") && (_sunFacesPortlet) &&
490                            (renderKitFactoryEl == null))) {
491    
492                            renderKitFactoryEl = factoryEl.addElement("render-kit-factory");
493    
494                            renderKitFactoryEl.addText(LIFERAY_RENDER_KIT_FACTORY);
495                    }
496                    else if (_myFacesPortlet && (facesContextFactoryEl == null)) {
497                            facesContextFactoryEl = factoryEl.addElement(
498                                    "faces-context-factory");
499    
500                            facesContextFactoryEl.addText(MYFACES_CONTEXT_FACTORY);
501                    }
502    
503                    if (!appServerType.equals("orion") && (_sunFacesPortlet)) {
504                            factoryEl.detach();
505                    }
506    
507                    XMLMerger merger = new XMLMerger(new FacesXMLDescriptor());
508    
509                    DocumentImpl docImpl = (DocumentImpl)doc;
510    
511                    merger.organizeXML(docImpl.getWrappedDocument());
512    
513                    FileUtil.write(facesXML, doc.formattedString(), true);
514            }
515    
516            protected void updateDeployDirectory(File srcFile) throws Exception {
517                    try {
518                            if (!PrefsPropsUtil.getBoolean(
519                                            PropsKeys.AUTO_DEPLOY_CUSTOM_PORTLET_XML,
520                                            PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML)) {
521    
522                                    return;
523                            }
524                    }
525                    catch (Exception e) {
526    
527                            // This will only happen when running the deploy tool in Ant in the
528                            // classical way where the WAR file is actually massaged and
529                            // packaged.
530    
531                            if (!PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML) {
532                                    return;
533                            }
534                    }
535    
536                    File portletXML = new File(
537                            srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD);
538    
539                    if (portletXML.exists()) {
540                            File portletCustomXML = new File(
541                                    srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM);
542    
543                            if (portletCustomXML.exists()) {
544                                    portletCustomXML.delete();
545                            }
546    
547                            portletXML.renameTo(portletCustomXML);
548                    }
549            }
550    
551            protected void updatePortletXML(File portletXML) throws Exception {
552                    if (!portletXML.exists()) {
553                            return;
554                    }
555    
556                    String content = FileUtil.read(portletXML);
557    
558                    content = StringUtil.replace(
559                            content, "com.liferay.util.bridges.jsp.JSPPortlet",
560                            MVCPortlet.class.getName());
561    
562                    FileUtil.write(portletXML, content);
563            }
564    
565            private boolean _myFacesPortlet;
566            private boolean _sunFacesPortlet;
567    
568    }