001 /** 002 * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved. 003 * 004 * The contents of this file are subject to the terms of the Liferay Enterprise 005 * Subscription License ("License"). You may not use this file except in 006 * compliance with the License. You can obtain a copy of the License by 007 * contacting Liferay, Inc. See the License for the specific language governing 008 * permissions and limitations under the License, including but not limited to 009 * distribution rights of the Software. 010 * 011 * 012 * 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 // Ignore filters 167 168 sb.append(getIgnoreFiltersContent(srcFile)); 169 170 // Speed filters 171 172 sb.append(getSpeedFiltersContent(srcFile)); 173 174 return sb.toString(); 175 } 176 177 protected String getServletContent(File portletXML, File webXML) 178 throws Exception { 179 180 StringBundler sb = new StringBundler(); 181 182 // Add wrappers for portlets 183 184 Document doc = SAXReaderUtil.read(portletXML); 185 186 Element root = doc.getRootElement(); 187 188 Iterator<Element> itr1 = root.elements("portlet").iterator(); 189 190 while (itr1.hasNext()) { 191 Element portlet = itr1.next(); 192 193 String portletName = PortalUtil.getJsSafePortletId( 194 portlet.elementText("portlet-name")); 195 String portletClass = portlet.elementText("portlet-class"); 196 197 sb.append("<servlet>"); 198 sb.append("<servlet-name>"); 199 sb.append(portletName); 200 sb.append("</servlet-name>"); 201 sb.append("<servlet-class>"); 202 sb.append("com.liferay.portal.kernel.servlet.PortletServlet"); 203 sb.append("</servlet-class>"); 204 sb.append("<init-param>"); 205 sb.append("<param-name>portlet-class</param-name>"); 206 sb.append("<param-value>"); 207 sb.append(portletClass); 208 sb.append("</param-value>"); 209 sb.append("</init-param>"); 210 sb.append("<load-on-startup>0</load-on-startup>"); 211 sb.append("</servlet>"); 212 213 sb.append("<servlet-mapping>"); 214 sb.append("<servlet-name>"); 215 sb.append(portletName); 216 sb.append("</servlet-name>"); 217 sb.append("<url-pattern>/"); 218 sb.append(portletName); 219 sb.append("/*</url-pattern>"); 220 sb.append("</servlet-mapping>"); 221 } 222 223 // Make sure there is a company id specified 224 225 doc = SAXReaderUtil.read(webXML); 226 227 root = doc.getRootElement(); 228 229 // Remove deprecated references to SharedServletWrapper 230 231 itr1 = root.elements("servlet").iterator(); 232 233 while (itr1.hasNext()) { 234 Element servlet = itr1.next(); 235 236 String icon = servlet.elementText("icon"); 237 String servletName = servlet.elementText("servlet-name"); 238 String displayName = servlet.elementText("display-name"); 239 String description = servlet.elementText("description"); 240 String servletClass = servlet.elementText("servlet-class"); 241 List<Element> initParams = servlet.elements("init-param"); 242 String loadOnStartup = servlet.elementText("load-on-startup"); 243 String runAs = servlet.elementText("run-as"); 244 List<Element> securityRoleRefs = servlet.elements( 245 "security-role-ref"); 246 247 if ((servletClass != null) && 248 (servletClass.equals( 249 "com.liferay.portal.servlet.SharedServletWrapper"))) { 250 251 sb.append("<servlet>"); 252 253 if (icon != null) { 254 sb.append("<icon>"); 255 sb.append(icon); 256 sb.append("</icon>"); 257 } 258 259 if (servletName != null) { 260 sb.append("<servlet-name>"); 261 sb.append(servletName); 262 sb.append("</servlet-name>"); 263 } 264 265 if (displayName != null) { 266 sb.append("<display-name>"); 267 sb.append(displayName); 268 sb.append("</display-name>"); 269 } 270 271 if (description != null) { 272 sb.append("<description>"); 273 sb.append(description); 274 sb.append("</description>"); 275 } 276 277 Iterator<Element> itr2 = initParams.iterator(); 278 279 while (itr2.hasNext()) { 280 Element initParam = itr2.next(); 281 282 String paramName = initParam.elementText("param-name"); 283 String paramValue = initParam.elementText("param-value"); 284 285 if ((paramName != null) && 286 (paramName.equals("servlet-class"))) { 287 288 sb.append("<servlet-class>"); 289 sb.append(paramValue); 290 sb.append("</servlet-class>"); 291 } 292 } 293 294 itr2 = initParams.iterator(); 295 296 while (itr2.hasNext()) { 297 Element initParam = itr2.next(); 298 299 String paramName = initParam.elementText("param-name"); 300 String paramValue = initParam.elementText("param-value"); 301 String paramDesc = initParam.elementText("description"); 302 303 if ((paramName != null) && 304 (!paramName.equals("servlet-class"))) { 305 306 sb.append("<init-param>"); 307 sb.append("<param-name>"); 308 sb.append(paramName); 309 sb.append("</param-name>"); 310 311 if (paramValue != null) { 312 sb.append("<param-value>"); 313 sb.append(paramValue); 314 sb.append("</param-value>"); 315 } 316 317 if (paramDesc != null) { 318 sb.append("<description>"); 319 sb.append(paramDesc); 320 sb.append("</description>"); 321 } 322 323 sb.append("</init-param>"); 324 } 325 } 326 327 if (loadOnStartup != null) { 328 sb.append("<load-on-startup>"); 329 sb.append(loadOnStartup); 330 sb.append("</load-on-startup>"); 331 } 332 333 if (runAs != null) { 334 sb.append("<run-as>"); 335 sb.append(runAs); 336 sb.append("</run-as>"); 337 } 338 339 itr2 = securityRoleRefs.iterator(); 340 341 while (itr2.hasNext()) { 342 Element roleRef = itr2.next(); 343 344 String roleDesc = roleRef.elementText("description"); 345 String roleName = roleRef.elementText("role-name"); 346 String roleLink = roleRef.elementText("role-link"); 347 348 sb.append("<security-role-ref>"); 349 350 if (roleDesc != null) { 351 sb.append("<description>"); 352 sb.append(roleDesc); 353 sb.append("</description>"); 354 } 355 356 if (roleName != null) { 357 sb.append("<role-name>"); 358 sb.append(roleName); 359 sb.append("</role-name>"); 360 } 361 362 if (roleLink != null) { 363 sb.append("<role-link>"); 364 sb.append(roleLink); 365 sb.append("</role-link>"); 366 } 367 368 sb.append("</security-role-ref>"); 369 } 370 371 sb.append("</servlet>"); 372 } 373 } 374 375 return sb.toString(); 376 } 377 378 protected void processPluginPackageProperties( 379 File srcFile, String displayName, PluginPackage pluginPackage) 380 throws Exception { 381 382 if (pluginPackage == null) { 383 return; 384 } 385 386 Properties properties = getPluginPackageProperties(srcFile); 387 388 if ((properties == null) || (properties.size() == 0)) { 389 return; 390 } 391 392 String moduleGroupId = pluginPackage.getGroupId(); 393 String moduleArtifactId = pluginPackage.getArtifactId(); 394 String moduleVersion = pluginPackage.getVersion(); 395 396 String pluginName = pluginPackage.getName(); 397 String pluginType = pluginPackage.getTypes().get(0); 398 String pluginTypeName = TextFormatter.format( 399 pluginType, TextFormatter.J); 400 401 if (!pluginType.equals(Plugin.TYPE_PORTLET)) { 402 return; 403 } 404 405 String tags = getPluginPackageTagsXml(pluginPackage.getTags()); 406 String shortDescription = pluginPackage.getShortDescription(); 407 String longDescription = pluginPackage.getLongDescription(); 408 String changeLog = pluginPackage.getChangeLog(); 409 String pageURL = pluginPackage.getPageURL(); 410 String author = pluginPackage.getAuthor(); 411 String licenses = getPluginPackageLicensesXml( 412 pluginPackage.getLicenses()); 413 String liferayVersions = getPluginPackageLiferayVersionsXml( 414 pluginPackage.getLiferayVersions()); 415 416 Map<String, String> filterMap = new HashMap<String, String>(); 417 418 filterMap.put("module_group_id", moduleGroupId); 419 filterMap.put("module_artifact_id", moduleArtifactId); 420 filterMap.put("module_version", moduleVersion); 421 422 filterMap.put("plugin_name", pluginName); 423 filterMap.put("plugin_type", pluginType); 424 filterMap.put("plugin_type_name", pluginTypeName); 425 426 filterMap.put("tags", tags); 427 filterMap.put("short_description", shortDescription); 428 filterMap.put("long_description", longDescription); 429 filterMap.put("change_log", changeLog); 430 filterMap.put("page_url", pageURL); 431 filterMap.put("author", author); 432 filterMap.put("licenses", licenses); 433 filterMap.put("liferay_versions", liferayVersions); 434 435 copyDependencyXml( 436 "liferay-plugin-package.xml", srcFile + "/WEB-INF", filterMap, 437 true); 438 } 439 440 protected void setupJSF(File facesXML, File portletXML) throws Exception { 441 _myFacesPortlet = false; 442 _sunFacesPortlet = false; 443 444 if (!facesXML.exists()) { 445 return; 446 } 447 448 // portlet.xml 449 450 Document doc = SAXReaderUtil.read(portletXML, true); 451 452 Element root = doc.getRootElement(); 453 454 List<Element> elements = root.elements("portlet"); 455 456 Iterator<Element> itr = elements.iterator(); 457 458 while (itr.hasNext()) { 459 Element portlet = itr.next(); 460 461 String portletClass = portlet.elementText("portlet-class"); 462 463 if (portletClass.equals(JSF_MYFACES)) { 464 _myFacesPortlet = true; 465 466 break; 467 } 468 else if (portletClass.equals(JSF_SUN)) { 469 _sunFacesPortlet = true; 470 471 break; 472 } 473 } 474 475 // faces-config.xml 476 477 doc = SAXReaderUtil.read(facesXML, true); 478 479 root = doc.getRootElement(); 480 481 Element factoryEl = root.element("factory"); 482 483 Element renderKitFactoryEl = null; 484 Element facesContextFactoryEl = null; 485 486 if (factoryEl == null) { 487 factoryEl = root.addElement("factory"); 488 } 489 490 renderKitFactoryEl = factoryEl.element("render-kit-factory"); 491 facesContextFactoryEl = factoryEl.element("faces-context-factory"); 492 493 if ((appServerType.equals("orion") && (_sunFacesPortlet) && 494 (renderKitFactoryEl == null))) { 495 496 renderKitFactoryEl = factoryEl.addElement("render-kit-factory"); 497 498 renderKitFactoryEl.addText(LIFERAY_RENDER_KIT_FACTORY); 499 } 500 else if (_myFacesPortlet && (facesContextFactoryEl == null)) { 501 facesContextFactoryEl = factoryEl.addElement( 502 "faces-context-factory"); 503 504 facesContextFactoryEl.addText(MYFACES_CONTEXT_FACTORY); 505 } 506 507 if (!appServerType.equals("orion") && (_sunFacesPortlet)) { 508 factoryEl.detach(); 509 } 510 511 XMLMerger merger = new XMLMerger(new FacesXMLDescriptor()); 512 513 DocumentImpl docImpl = (DocumentImpl)doc; 514 515 merger.organizeXML(docImpl.getWrappedDocument()); 516 517 FileUtil.write(facesXML, doc.formattedString(), true); 518 } 519 520 protected void updateDeployDirectory(File srcFile) throws Exception { 521 try { 522 if (!PrefsPropsUtil.getBoolean( 523 PropsKeys.AUTO_DEPLOY_CUSTOM_PORTLET_XML, 524 PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML)) { 525 526 return; 527 } 528 } 529 catch (Exception e) { 530 531 // This will only happen when running the deploy tool in Ant in the 532 // classical way where the WAR file is actually massaged and 533 // packaged. 534 535 if (!PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML) { 536 return; 537 } 538 } 539 540 File portletXML = new File( 541 srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD); 542 543 if (portletXML.exists()) { 544 File portletCustomXML = new File( 545 srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM); 546 547 if (portletCustomXML.exists()) { 548 portletCustomXML.delete(); 549 } 550 551 portletXML.renameTo(portletCustomXML); 552 } 553 } 554 555 protected void updatePortletXML(File portletXML) throws Exception { 556 if (!portletXML.exists()) { 557 return; 558 } 559 560 String content = FileUtil.read(portletXML); 561 562 content = StringUtil.replace( 563 content, "com.liferay.util.bridges.jsp.JSPPortlet", 564 MVCPortlet.class.getName()); 565 566 FileUtil.write(portletXML, content); 567 } 568 569 private boolean _myFacesPortlet; 570 private boolean _sunFacesPortlet; 571 572 }