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