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