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