001 /** 002 * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved. 003 * 004 * This library is free software; you can redistribute it and/or modify it under 005 * the terms of the GNU Lesser General Public License as published by the Free 006 * Software Foundation; either version 2.1 of the License, or (at your option) 007 * any later version. 008 * 009 * This library is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 011 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 012 * details. 013 */ 014 015 package com.liferay.portal.tools.deploy; 016 017 import com.liferay.portal.kernel.plugin.PluginPackage; 018 import com.liferay.portal.kernel.util.FileUtil; 019 import com.liferay.portal.kernel.util.PropsKeys; 020 import com.liferay.portal.kernel.util.ServerDetector; 021 import com.liferay.portal.kernel.util.StringBundler; 022 import com.liferay.portal.kernel.util.StringUtil; 023 import com.liferay.portal.kernel.util.Validator; 024 import com.liferay.portal.kernel.xml.Document; 025 import com.liferay.portal.kernel.xml.Element; 026 import com.liferay.portal.kernel.xml.SAXReaderUtil; 027 import com.liferay.portal.model.Plugin; 028 import com.liferay.portal.util.InitUtil; 029 import com.liferay.portal.util.Portal; 030 import com.liferay.portal.util.PortalUtil; 031 import com.liferay.portal.util.PrefsPropsUtil; 032 import com.liferay.portal.util.PropsValues; 033 import com.liferay.portal.xml.DocumentImpl; 034 import com.liferay.util.TextFormatter; 035 import com.liferay.util.bridges.mvc.MVCPortlet; 036 import com.liferay.util.xml.XMLMerger; 037 import com.liferay.util.xml.descriptor.FacesXMLDescriptor; 038 039 import java.io.File; 040 041 import java.util.ArrayList; 042 import java.util.HashMap; 043 import java.util.Iterator; 044 import java.util.List; 045 import java.util.Map; 046 import java.util.Properties; 047 048 /** 049 * @author Brian Wing Shun Chan 050 * @author Brian Myunghun Kim 051 */ 052 public class PortletDeployer extends BaseDeployer { 053 054 public static final String JSF_MYFACES = 055 "org.apache.myfaces.portlet.MyFacesGenericPortlet"; 056 057 public static final String JSF_STANDARD = 058 "javax.portlet.faces.GenericFacesPortlet"; 059 060 public static final String JSF_SUN = 061 "com.sun.faces.portlet.FacesPortlet"; 062 063 public static final String LIFERAY_RENDER_KIT_FACTORY = 064 "com.liferay.util.jsf.sun.faces.renderkit.LiferayRenderKitFactoryImpl"; 065 066 public static final String MYFACES_CONTEXT_FACTORY = 067 "com.liferay.util.bridges.jsf.myfaces.MyFacesContextFactoryImpl"; 068 069 public static void main(String[] args) { 070 InitUtil.initWithSpring(); 071 072 List<String> wars = new ArrayList<String>(); 073 List<String> jars = new ArrayList<String>(); 074 075 for (String arg : args) { 076 if (arg.endsWith(".war")) { 077 wars.add(arg); 078 } 079 else if (arg.endsWith(".jar")) { 080 jars.add(arg); 081 } 082 } 083 084 new PortletDeployer(wars, jars); 085 } 086 087 protected PortletDeployer() { 088 } 089 090 protected PortletDeployer(List<String> wars, List<String> jars) { 091 super(wars, jars); 092 } 093 094 protected void checkArguments() { 095 super.checkArguments(); 096 097 if (Validator.isNull(portletTaglibDTD)) { 098 throw new IllegalArgumentException( 099 "The system property deployer.portlet.taglib.dtd is not set"); 100 } 101 } 102 103 protected void copyXmls( 104 File srcFile, String displayName, PluginPackage pluginPackage) 105 throws Exception { 106 107 super.copyXmls(srcFile, displayName, pluginPackage); 108 109 if (appServerType.equals(ServerDetector.TOMCAT_ID)) { 110 copyDependencyXml("context.xml", srcFile + "/META-INF"); 111 } 112 } 113 114 protected String getExtraContent( 115 double webXmlVersion, File srcFile, String displayName) 116 throws Exception { 117 118 StringBundler sb = new StringBundler(); 119 120 String extraContent = super.getExtraContent( 121 webXmlVersion, srcFile, displayName); 122 123 sb.append(extraContent); 124 125 if (ServerDetector.isWebSphere()) { 126 sb.append("<context-param>"); 127 sb.append("<param-name>"); 128 sb.append("com.ibm.websphere.portletcontainer."); 129 sb.append("PortletDeploymentEnabled"); 130 sb.append("</param-name>"); 131 sb.append("<param-value>false</param-value>"); 132 sb.append("</context-param>"); 133 } 134 135 File facesXML = new File(srcFile + "/WEB-INF/faces-config.xml"); 136 File portletXML = new File( 137 srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD); 138 File webXML = new File(srcFile + "/WEB-INF/web.xml"); 139 140 updatePortletXML(portletXML); 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 StringBundler sb = new StringBundler(); 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 properties = getPluginPackageProperties(srcFile); 383 384 if ((properties == null) || (properties.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 = factoryEl.addElement( 498 "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 protected void updatePortletXML(File portletXML) throws Exception { 552 if (!portletXML.exists()) { 553 return; 554 } 555 556 String content = FileUtil.read(portletXML); 557 558 content = StringUtil.replace( 559 content, "com.liferay.util.bridges.jsp.JSPPortlet", 560 MVCPortlet.class.getName()); 561 562 FileUtil.write(portletXML, content); 563 } 564 565 private boolean _myFacesPortlet; 566 private boolean _sunFacesPortlet; 567 568 }