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