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