001 /** 002 * Copyright (c) 2000-2011 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.GetterUtil; 020 import com.liferay.portal.kernel.util.PropsKeys; 021 import com.liferay.portal.kernel.util.ServerDetector; 022 import com.liferay.portal.kernel.util.StringBundler; 023 import com.liferay.portal.kernel.util.StringUtil; 024 import com.liferay.portal.kernel.util.Validator; 025 import com.liferay.portal.kernel.xml.Document; 026 import com.liferay.portal.kernel.xml.Element; 027 import com.liferay.portal.kernel.xml.SAXReaderUtil; 028 import com.liferay.portal.model.Plugin; 029 import com.liferay.portal.util.InitUtil; 030 import com.liferay.portal.util.Portal; 031 import com.liferay.portal.util.PortalUtil; 032 import com.liferay.portal.util.PrefsPropsUtil; 033 import com.liferay.portal.util.PropsValues; 034 import com.liferay.portal.xml.DocumentImpl; 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.Iterator; 043 import java.util.List; 044 045 /** 046 * @author Brian Wing Shun Chan 047 * @author Brian Myunghun Kim 048 */ 049 public class PortletDeployer extends BaseDeployer { 050 051 public static final String JSF_MYFACES = 052 "org.apache.myfaces.portlet.MyFacesGenericPortlet"; 053 054 public static final String JSF_STANDARD = 055 "javax.portlet.faces.GenericFacesPortlet"; 056 057 public static final String JSF_SUN = 058 "com.sun.faces.portlet.FacesPortlet"; 059 060 public static final String LIFERAY_RENDER_KIT_FACTORY = 061 "com.liferay.util.jsf.sun.faces.renderkit.LiferayRenderKitFactoryImpl"; 062 063 public static final String MYFACES_CONTEXT_FACTORY = 064 "com.liferay.util.bridges.jsf.myfaces.MyFacesContextFactoryImpl"; 065 066 public static void main(String[] args) { 067 InitUtil.initWithSpring(); 068 069 List<String> wars = new ArrayList<String>(); 070 List<String> jars = new ArrayList<String>(); 071 072 for (String arg : args) { 073 if (arg.endsWith(".war")) { 074 wars.add(arg); 075 } 076 else if (arg.endsWith(".jar")) { 077 jars.add(arg); 078 } 079 } 080 081 new PortletDeployer(wars, jars); 082 } 083 084 public PortletDeployer() { 085 } 086 087 public PortletDeployer(List<String> wars, List<String> jars) { 088 super(wars, jars); 089 } 090 091 @Override 092 public void checkArguments() { 093 super.checkArguments(); 094 095 if (Validator.isNull(portletTaglibDTD)) { 096 throw new IllegalArgumentException( 097 "The system property deployer.portlet.taglib.dtd is not set"); 098 } 099 } 100 101 @Override 102 public void copyXmls( 103 File srcFile, String displayName, PluginPackage pluginPackage) 104 throws Exception { 105 106 super.copyXmls(srcFile, displayName, pluginPackage); 107 108 if (appServerType.equals(ServerDetector.TOMCAT_ID)) { 109 copyDependencyXml("context.xml", srcFile + "/META-INF"); 110 } 111 112 copyDependencyXml( 113 "_servlet_context_include.jsp", srcFile + "/WEB-INF/jsp"); 114 } 115 116 @Override 117 public String getExtraContent( 118 double webXmlVersion, File srcFile, String displayName) 119 throws Exception { 120 121 StringBundler sb = new StringBundler(); 122 123 String extraContent = super.getExtraContent( 124 webXmlVersion, srcFile, displayName); 125 126 sb.append(extraContent); 127 128 if (ServerDetector.isWebSphere()) { 129 sb.append("<context-param>"); 130 sb.append("<param-name>"); 131 sb.append("com.ibm.websphere.portletcontainer."); 132 sb.append("PortletDeploymentEnabled"); 133 sb.append("</param-name>"); 134 sb.append("<param-value>false</param-value>"); 135 sb.append("</context-param>"); 136 } 137 138 File facesXML = new File(srcFile + "/WEB-INF/faces-config.xml"); 139 File portletXML = new File( 140 srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD); 141 File webXML = new File(srcFile + "/WEB-INF/web.xml"); 142 143 updatePortletXML(portletXML); 144 145 sb.append(getServletContent(portletXML, webXML)); 146 147 setupJSF(facesXML, portletXML); 148 149 if (_sunFacesPortlet) { 150 151 // LiferayConfigureListener 152 153 sb.append("<listener>"); 154 sb.append("<listener-class>"); 155 sb.append("com.liferay.util.bridges.jsf.sun."); 156 sb.append("LiferayConfigureListener"); 157 sb.append("</listener-class>"); 158 sb.append("</listener>"); 159 } 160 161 // PortletContextListener 162 163 sb.append("<listener>"); 164 sb.append("<listener-class>"); 165 sb.append("com.liferay.portal.kernel.servlet.PortletContextListener"); 166 sb.append("</listener-class>"); 167 sb.append("</listener>"); 168 169 // Ignore filters 170 171 sb.append(getIgnoreFiltersContent(srcFile)); 172 173 // Speed filters 174 175 sb.append(getSpeedFiltersContent(srcFile)); 176 177 // Servlet context include filters 178 179 sb.append( 180 getServletContextIncludeFiltersContent(webXmlVersion, srcFile)); 181 182 return sb.toString(); 183 } 184 185 @Override 186 public String getPluginType() { 187 return Plugin.TYPE_PORTLET; 188 } 189 190 public String getServletContent(File portletXML, File webXML) 191 throws Exception { 192 193 StringBundler sb = new StringBundler(); 194 195 // Add wrappers for portlets 196 197 Document doc = SAXReaderUtil.read(portletXML); 198 199 Element root = doc.getRootElement(); 200 201 Iterator<Element> itr1 = root.elements("portlet").iterator(); 202 203 while (itr1.hasNext()) { 204 Element portlet = itr1.next(); 205 206 String portletName = PortalUtil.getJsSafePortletId( 207 portlet.elementText("portlet-name")); 208 String portletClass = portlet.elementText("portlet-class"); 209 210 String servletName = portletName + " Servlet"; 211 212 sb.append("<servlet>"); 213 sb.append("<servlet-name>"); 214 sb.append(servletName); 215 sb.append("</servlet-name>"); 216 sb.append("<servlet-class>"); 217 sb.append("com.liferay.portal.kernel.servlet.PortletServlet"); 218 sb.append("</servlet-class>"); 219 sb.append("<init-param>"); 220 sb.append("<param-name>portlet-class</param-name>"); 221 sb.append("<param-value>"); 222 sb.append(portletClass); 223 sb.append("</param-value>"); 224 sb.append("</init-param>"); 225 sb.append("<load-on-startup>0</load-on-startup>"); 226 sb.append("</servlet>"); 227 228 sb.append("<servlet-mapping>"); 229 sb.append("<servlet-name>"); 230 sb.append(servletName); 231 sb.append("</servlet-name>"); 232 sb.append("<url-pattern>/"); 233 sb.append(portletName); 234 sb.append("/*</url-pattern>"); 235 sb.append("</servlet-mapping>"); 236 } 237 238 // Make sure there is a company id specified 239 240 doc = SAXReaderUtil.read(webXML); 241 242 root = doc.getRootElement(); 243 244 // Remove deprecated references to SharedServletWrapper 245 246 itr1 = root.elements("servlet").iterator(); 247 248 while (itr1.hasNext()) { 249 Element servlet = itr1.next(); 250 251 String icon = servlet.elementText("icon"); 252 String servletName = servlet.elementText("servlet-name"); 253 String displayName = servlet.elementText("display-name"); 254 String description = servlet.elementText("description"); 255 String servletClass = servlet.elementText("servlet-class"); 256 List<Element> initParams = servlet.elements("init-param"); 257 String loadOnStartup = servlet.elementText("load-on-startup"); 258 String runAs = servlet.elementText("run-as"); 259 List<Element> securityRoleRefs = servlet.elements( 260 "security-role-ref"); 261 262 if ((servletClass != null) && 263 (servletClass.equals( 264 "com.liferay.portal.servlet.SharedServletWrapper"))) { 265 266 sb.append("<servlet>"); 267 268 if (icon != null) { 269 sb.append("<icon>"); 270 sb.append(icon); 271 sb.append("</icon>"); 272 } 273 274 if (servletName != null) { 275 sb.append("<servlet-name>"); 276 sb.append(servletName); 277 sb.append("</servlet-name>"); 278 } 279 280 if (displayName != null) { 281 sb.append("<display-name>"); 282 sb.append(displayName); 283 sb.append("</display-name>"); 284 } 285 286 if (description != null) { 287 sb.append("<description>"); 288 sb.append(description); 289 sb.append("</description>"); 290 } 291 292 Iterator<Element> itr2 = initParams.iterator(); 293 294 while (itr2.hasNext()) { 295 Element initParam = itr2.next(); 296 297 String paramName = initParam.elementText("param-name"); 298 String paramValue = initParam.elementText("param-value"); 299 300 if ((paramName != null) && 301 (paramName.equals("servlet-class"))) { 302 303 sb.append("<servlet-class>"); 304 sb.append(paramValue); 305 sb.append("</servlet-class>"); 306 } 307 } 308 309 itr2 = initParams.iterator(); 310 311 while (itr2.hasNext()) { 312 Element initParam = itr2.next(); 313 314 String paramName = initParam.elementText("param-name"); 315 String paramValue = initParam.elementText("param-value"); 316 String paramDesc = initParam.elementText("description"); 317 318 if ((paramName != null) && 319 (!paramName.equals("servlet-class"))) { 320 321 sb.append("<init-param>"); 322 sb.append("<param-name>"); 323 sb.append(paramName); 324 sb.append("</param-name>"); 325 326 if (paramValue != null) { 327 sb.append("<param-value>"); 328 sb.append(paramValue); 329 sb.append("</param-value>"); 330 } 331 332 if (paramDesc != null) { 333 sb.append("<description>"); 334 sb.append(paramDesc); 335 sb.append("</description>"); 336 } 337 338 sb.append("</init-param>"); 339 } 340 } 341 342 if (loadOnStartup != null) { 343 sb.append("<load-on-startup>"); 344 sb.append(loadOnStartup); 345 sb.append("</load-on-startup>"); 346 } 347 348 if (runAs != null) { 349 sb.append("<run-as>"); 350 sb.append(runAs); 351 sb.append("</run-as>"); 352 } 353 354 itr2 = securityRoleRefs.iterator(); 355 356 while (itr2.hasNext()) { 357 Element roleRef = itr2.next(); 358 359 String roleDesc = roleRef.elementText("description"); 360 String roleName = roleRef.elementText("role-name"); 361 String roleLink = roleRef.elementText("role-link"); 362 363 sb.append("<security-role-ref>"); 364 365 if (roleDesc != null) { 366 sb.append("<description>"); 367 sb.append(roleDesc); 368 sb.append("</description>"); 369 } 370 371 if (roleName != null) { 372 sb.append("<role-name>"); 373 sb.append(roleName); 374 sb.append("</role-name>"); 375 } 376 377 if (roleLink != null) { 378 sb.append("<role-link>"); 379 sb.append(roleLink); 380 sb.append("</role-link>"); 381 } 382 383 sb.append("</security-role-ref>"); 384 } 385 386 sb.append("</servlet>"); 387 } 388 } 389 390 return sb.toString(); 391 } 392 393 public void setupJSF(File facesXML, File portletXML) throws Exception { 394 _myFacesPortlet = false; 395 _sunFacesPortlet = false; 396 397 if (!facesXML.exists()) { 398 return; 399 } 400 401 // portlet.xml 402 403 Document doc = SAXReaderUtil.read(portletXML, true); 404 405 Element root = doc.getRootElement(); 406 407 List<Element> elements = root.elements("portlet"); 408 409 Iterator<Element> itr = elements.iterator(); 410 411 while (itr.hasNext()) { 412 Element portlet = itr.next(); 413 414 String portletClass = portlet.elementText("portlet-class"); 415 416 if (portletClass.equals(JSF_MYFACES)) { 417 _myFacesPortlet = true; 418 419 break; 420 } 421 else if (portletClass.equals(JSF_SUN)) { 422 _sunFacesPortlet = true; 423 424 break; 425 } 426 } 427 428 // faces-config.xml 429 430 doc = SAXReaderUtil.read(facesXML, true); 431 432 root = doc.getRootElement(); 433 434 Element factoryEl = root.element("factory"); 435 436 Element renderKitFactoryEl = null; 437 Element facesContextFactoryEl = null; 438 439 if (factoryEl == null) { 440 factoryEl = root.addElement("factory"); 441 } 442 443 renderKitFactoryEl = factoryEl.element("render-kit-factory"); 444 facesContextFactoryEl = factoryEl.element("faces-context-factory"); 445 446 if ((appServerType.equals("orion") && (_sunFacesPortlet) && 447 (renderKitFactoryEl == null))) { 448 449 renderKitFactoryEl = factoryEl.addElement("render-kit-factory"); 450 451 renderKitFactoryEl.addText(LIFERAY_RENDER_KIT_FACTORY); 452 } 453 else if (_myFacesPortlet && (facesContextFactoryEl == null)) { 454 facesContextFactoryEl = factoryEl.addElement( 455 "faces-context-factory"); 456 457 facesContextFactoryEl.addText(MYFACES_CONTEXT_FACTORY); 458 } 459 460 if (!appServerType.equals("orion") && (_sunFacesPortlet)) { 461 factoryEl.detach(); 462 } 463 464 XMLMerger merger = new XMLMerger(new FacesXMLDescriptor()); 465 466 DocumentImpl docImpl = (DocumentImpl)doc; 467 468 merger.organizeXML(docImpl.getWrappedDocument()); 469 470 FileUtil.write(facesXML, doc.formattedString(), true); 471 } 472 473 @Override 474 public void updateDeployDirectory(File srcFile) throws Exception { 475 boolean customPortletXML = false; 476 477 try { 478 customPortletXML = PrefsPropsUtil.getBoolean( 479 PropsKeys.AUTO_DEPLOY_CUSTOM_PORTLET_XML, 480 PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML); 481 } 482 catch (Exception e) { 483 484 // This will only happen when running the deploy tool in Ant in the 485 // classical way where the WAR file is actually massaged and 486 // packaged. 487 488 customPortletXML = PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML; 489 } 490 491 customPortletXML = GetterUtil.getBoolean( 492 System.getProperty("deployer.custom.portlet.xml"), 493 customPortletXML); 494 495 if (!customPortletXML) { 496 return; 497 } 498 499 File portletXML = new File( 500 srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD); 501 502 if (portletXML.exists()) { 503 File portletCustomXML = new File( 504 srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM); 505 506 if (portletCustomXML.exists()) { 507 portletCustomXML.delete(); 508 } 509 510 portletXML.renameTo(portletCustomXML); 511 } 512 } 513 514 public void updatePortletXML(File portletXML) throws Exception { 515 if (!portletXML.exists()) { 516 return; 517 } 518 519 String content = FileUtil.read(portletXML); 520 521 content = StringUtil.replace( 522 content, "com.liferay.util.bridges.jsp.JSPPortlet", 523 MVCPortlet.class.getName()); 524 525 FileUtil.write(portletXML, content); 526 } 527 528 private boolean _myFacesPortlet; 529 private boolean _sunFacesPortlet; 530 531 }