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