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