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