1   /**
2    * Copyright (c) 2000-2010 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   *
12   * 
13   */
14  
15  package com.liferay.portal.tools;
16  
17  import com.liferay.portal.deploy.DeployUtil;
18  import com.liferay.portal.kernel.deploy.auto.AutoDeployException;
19  import com.liferay.portal.kernel.log.Log;
20  import com.liferay.portal.kernel.log.LogFactoryUtil;
21  import com.liferay.portal.kernel.plugin.License;
22  import com.liferay.portal.kernel.plugin.PluginPackage;
23  import com.liferay.portal.kernel.util.FileUtil;
24  import com.liferay.portal.kernel.util.GetterUtil;
25  import com.liferay.portal.kernel.util.HttpUtil;
26  import com.liferay.portal.kernel.util.PropertiesUtil;
27  import com.liferay.portal.kernel.util.PropsKeys;
28  import com.liferay.portal.kernel.util.ServerDetector;
29  import com.liferay.portal.kernel.util.StringPool;
30  import com.liferay.portal.kernel.util.StringUtil;
31  import com.liferay.portal.kernel.util.Time;
32  import com.liferay.portal.kernel.util.Validator;
33  import com.liferay.portal.kernel.xml.Document;
34  import com.liferay.portal.kernel.xml.Element;
35  import com.liferay.portal.kernel.xml.SAXReaderUtil;
36  import com.liferay.portal.plugin.PluginPackageUtil;
37  import com.liferay.portal.util.ExtRegistry;
38  import com.liferay.portal.util.InitUtil;
39  import com.liferay.portal.util.PortalUtil;
40  import com.liferay.portal.util.PrefsPropsUtil;
41  import com.liferay.portal.util.PropsUtil;
42  import com.liferay.portal.util.PropsValues;
43  import com.liferay.util.SystemProperties;
44  import com.liferay.util.ant.CopyTask;
45  import com.liferay.util.ant.DeleteTask;
46  import com.liferay.util.ant.ExpandTask;
47  import com.liferay.util.ant.UpToDateTask;
48  import com.liferay.util.ant.WarTask;
49  import com.liferay.util.xml.XMLFormatter;
50  
51  import java.io.File;
52  import java.io.FileInputStream;
53  import java.io.IOException;
54  import java.io.InputStream;
55  
56  import java.util.ArrayList;
57  import java.util.List;
58  import java.util.Map;
59  import java.util.Properties;
60  import java.util.Set;
61  import java.util.zip.ZipEntry;
62  import java.util.zip.ZipFile;
63  
64  import org.apache.oro.io.GlobFilenameFilter;
65  
66  /**
67   * <a href="BaseDeployer.java.html"><b><i>View Source</i></b></a>
68   *
69   * @author Brian Wing Shun Chan
70   */
71  public class BaseDeployer {
72  
73      public static final String DEPLOY_TO_PREFIX = "DEPLOY_TO__";
74  
75      public static void main(String[] args) {
76          InitUtil.initWithSpring();
77  
78          List<String> wars = new ArrayList<String>();
79          List<String> jars = new ArrayList<String>();
80  
81          for (String arg : args) {
82              String fileName = arg.toLowerCase();
83  
84              if (fileName.endsWith(".war")) {
85                  wars.add(arg);
86              }
87              else if (fileName.endsWith(".jar")) {
88                  jars.add(arg);
89              }
90          }
91  
92          new BaseDeployer(wars, jars);
93      }
94  
95      protected BaseDeployer() {
96      }
97  
98      protected BaseDeployer(List<String> wars, List<String> jars) {
99          baseDir = System.getProperty("deployer.base.dir");
100         destDir = System.getProperty("deployer.dest.dir");
101         appServerType = System.getProperty("deployer.app.server.type");
102         portletTaglibDTD = System.getProperty("deployer.portlet.taglib.dtd");
103         portletExtTaglibDTD = System.getProperty(
104             "deployer.portlet.ext.taglib.dtd");
105         securityTaglibDTD = System.getProperty("deployer.security.taglib.dtd");
106         themeTaglibDTD = System.getProperty("deployer.theme.taglib.dtd");
107         uiTaglibDTD = System.getProperty("deployer.ui.taglib.dtd");
108         utilTaglibDTD = System.getProperty("deployer.util.taglib.dtd");
109         unpackWar = GetterUtil.getBoolean(
110             System.getProperty("deployer.unpack.war"), true);
111         filePattern = System.getProperty("deployer.file.pattern");
112         jbossPrefix = GetterUtil.getString(
113             System.getProperty("deployer.jboss.prefix"));
114         tomcatLibDir = System.getProperty("deployer.tomcat.lib.dir");
115         this.wars = wars;
116         this.jars = jars;
117 
118         checkArguments();
119 
120         try {
121             deploy();
122         }
123         catch (Exception e) {
124             e.printStackTrace();
125         }
126     }
127 
128     protected void addExtJar(List<String> jars, String resource)
129         throws Exception {
130 
131         Set<String> servletContextNames = ExtRegistry.getServletContextNames();
132 
133         for (String servletContextName : servletContextNames) {
134             String extResource =
135                 "ext-" + servletContextName + resource.substring(3);
136 
137             String path = DeployUtil.getResourcePath(extResource);
138 
139             if (_log.isDebugEnabled()) {
140                 if (path == null) {
141                     _log.debug("Resource " + extResource + " is not available");
142                 }
143                 else {
144                     _log.debug(
145                         "Resource " + extResource + " is available at " + path);
146                 }
147             }
148 
149             if (path != null) {
150                 jars.add(path);
151             }
152         }
153     }
154 
155     protected void addRequiredJar(List<String> jars, String resource)
156         throws Exception {
157 
158         String path = DeployUtil.getResourcePath(resource);
159 
160         if (path == null) {
161             throw new RuntimeException(
162                 "Resource " + resource + " does not exist");
163         }
164 
165         if (_log.isDebugEnabled()) {
166             _log.debug("Resource " + resource + " is available at " + path);
167         }
168 
169         jars.add(path);
170     }
171 
172     protected void checkArguments() {
173         if (Validator.isNull(baseDir)) {
174             throw new IllegalArgumentException(
175                 "The system property deployer.base.dir is not set");
176         }
177 
178         if (Validator.isNull(destDir)) {
179             throw new IllegalArgumentException(
180                 "The system property deployer.dest.dir is not set");
181         }
182 
183         if (Validator.isNull(appServerType)) {
184             throw new IllegalArgumentException(
185                 "The system property deployer.app.server.type is not set");
186         }
187 
188         if (!appServerType.startsWith(ServerDetector.GERONIMO_ID) &&
189             !appServerType.startsWith(ServerDetector.GLASSFISH_ID) &&
190             !appServerType.startsWith(ServerDetector.JBOSS_ID) &&
191             !appServerType.startsWith(ServerDetector.JONAS_ID) &&
192             !appServerType.equals(ServerDetector.JETTY_ID) &&
193             !appServerType.equals(ServerDetector.OC4J_ID) &&
194             !appServerType.equals(ServerDetector.ORION_ID) &&
195             !appServerType.equals(ServerDetector.PRAMATI_ID) &&
196             !appServerType.equals(ServerDetector.RESIN_ID) &&
197             !appServerType.equals(ServerDetector.TOMCAT_ID) &&
198             !appServerType.equals(ServerDetector.WEBLOGIC_ID) &&
199             !appServerType.equals(ServerDetector.WEBSPHERE_ID)) {
200 
201             throw new IllegalArgumentException(
202                 appServerType + " is not a valid application server type");
203         }
204 
205         if (appServerType.startsWith(ServerDetector.GLASSFISH_ID) ||
206             appServerType.equals(ServerDetector.PRAMATI_ID) ||
207             appServerType.equals(ServerDetector.WEBLOGIC_ID)) {
208 
209             unpackWar = false;
210         }
211 
212         if (Validator.isNotNull(jbossPrefix) &&
213             !Validator.isNumber(jbossPrefix)) {
214 
215             jbossPrefix = "1";
216         }
217     }
218 
219     protected void copyDependencyXml(String fileName, String targetDir)
220         throws Exception {
221 
222         copyDependencyXml(fileName, targetDir, null);
223     }
224 
225     protected void copyDependencyXml(
226             String fileName, String targetDir, Map<String, String> filterMap)
227         throws Exception {
228 
229         copyDependencyXml(fileName, targetDir, filterMap, false);
230     }
231 
232     protected void copyDependencyXml(
233             String fileName, String targetDir, Map<String, String> filterMap,
234             boolean overwrite)
235         throws Exception {
236 
237         File file = new File(DeployUtil.getResourcePath(fileName));
238         File targetFile = new File(targetDir + "/" + fileName);
239 
240         if (!targetFile.exists()) {
241             CopyTask.copyFile(
242                 file, new File(targetDir), filterMap, overwrite, true);
243         }
244     }
245 
246     protected void copyJars(File srcFile, PluginPackage pluginPackage)
247         throws Exception {
248 
249         for (int i = 0; i < jars.size(); i++) {
250             String jarFullName = jars.get(i);
251 
252             String jarName = jarFullName.substring(
253                 jarFullName.lastIndexOf("/") + 1, jarFullName.length());
254 
255             if ((!appServerType.equals(ServerDetector.TOMCAT_ID)) ||
256                 (appServerType.equals(ServerDetector.TOMCAT_ID) &&
257                     !jarFullName.equals("util-java.jar"))) {
258 
259                 FileUtil.copyFile(
260                     jarFullName, srcFile + "/WEB-INF/lib/" + jarName, true);
261             }
262         }
263 
264         FileUtil.delete(srcFile + "/WEB-INF/lib/util-jsf.jar");
265     }
266 
267     protected void copyPortalDependencies(File srcFile) throws Exception {
268         Properties properties = getPluginPackageProperties(srcFile);
269 
270         if (properties == null) {
271             return;
272         }
273 
274         // jars
275 
276         String[] portalJars = StringUtil.split(
277             properties.getProperty(
278                 "portal-dependency-jars",
279                 properties.getProperty("portal.dependency.jars")));
280 
281         for (int i = 0; i < portalJars.length; i++) {
282             String portalJar = portalJars[i].trim();
283 
284             if (_log.isDebugEnabled()) {
285                 _log.debug("Copy portal JAR " + portalJar);
286             }
287 
288             try {
289                 String portalJarPath = PortalUtil.getPortalLibDir() + portalJar;
290 
291                 FileUtil.copyFile(
292                     portalJarPath, srcFile + "/WEB-INF/lib/" + portalJar, true);
293             }
294             catch (Exception e) {
295                 _log.error("Unable to copy portal JAR " + portalJar, e);
296             }
297         }
298 
299         // tlds
300 
301         String[] portalTlds = StringUtil.split(
302             properties.getProperty(
303                 "portal-dependency-tlds",
304                 properties.getProperty("portal.dependency.tlds")));
305 
306         for (int i = 0; i < portalTlds.length; i++) {
307             String portalTld = portalTlds[i].trim();
308 
309             if (_log.isDebugEnabled()) {
310                 _log.debug("Copy portal TLD " + portalTld);
311             }
312 
313             try {
314                 String portalTldPath = DeployUtil.getResourcePath(portalTld);
315 
316                 FileUtil.copyFile(
317                     portalTldPath, srcFile + "/WEB-INF/tld/" + portalTld, true);
318             }
319             catch (Exception e) {
320                 _log.error("Unable to copy portal TLD " + portalTld, e);
321             }
322         }
323 
324         // commons-logging*.jar
325 
326         File pluginLibDir = new File(srcFile + "/WEB-INF/lib/");
327 
328         String[] commonsLoggingJars = pluginLibDir.list(
329             new GlobFilenameFilter("commons-logging*.jar"));
330 
331         if ((commonsLoggingJars == null) || (commonsLoggingJars.length == 0)) {
332             String portalJarPath =
333                 PortalUtil.getPortalLibDir() + "commons-logging.jar";
334 
335             FileUtil.copyFile(
336                 portalJarPath, srcFile + "/WEB-INF/lib/commons-logging.jar",
337                 true);
338         }
339 
340         // log4j*.jar
341 
342         String[] log4jJars = pluginLibDir.list(
343             new GlobFilenameFilter("log4j*.jar"));
344 
345         if ((log4jJars == null) || (log4jJars.length == 0)) {
346             String portalJarPath = PortalUtil.getPortalLibDir() + "log4j.jar";
347 
348             FileUtil.copyFile(
349                 portalJarPath, srcFile + "/WEB-INF/lib/log4j.jar", true);
350         }
351     }
352 
353     protected void copyProperties(File srcFile, PluginPackage pluginPackage)
354         throws Exception {
355 
356         copyDependencyXml("log4j.properties", srcFile + "/WEB-INF/classes");
357         copyDependencyXml("logging.properties", srcFile + "/WEB-INF/classes");
358     }
359 
360     protected void copyTlds(File srcFile, PluginPackage pluginPackage)
361         throws Exception {
362 
363         if (Validator.isNotNull(portletTaglibDTD)) {
364             FileUtil.copyFile(
365                 portletTaglibDTD, srcFile + "/WEB-INF/tld/liferay-portlet.tld",
366                 true);
367         }
368 
369         if (Validator.isNotNull(portletExtTaglibDTD)) {
370             FileUtil.copyFile(
371                 portletExtTaglibDTD,
372                 srcFile + "/WEB-INF/tld/liferay-portlet-ext.tld", true);
373         }
374 
375         if (Validator.isNotNull(securityTaglibDTD)) {
376             FileUtil.copyFile(
377                 securityTaglibDTD,
378                 srcFile + "/WEB-INF/tld/liferay-security.tld", true);
379         }
380 
381         if (Validator.isNotNull(themeTaglibDTD)) {
382             FileUtil.copyFile(
383                 themeTaglibDTD, srcFile + "/WEB-INF/tld/liferay-theme.tld",
384                 true);
385         }
386 
387         if (Validator.isNotNull(uiTaglibDTD)) {
388             FileUtil.copyFile(
389                 uiTaglibDTD, srcFile + "/WEB-INF/tld/liferay-ui.tld", true);
390         }
391 
392         if (Validator.isNotNull(utilTaglibDTD)) {
393             FileUtil.copyFile(
394                 utilTaglibDTD, srcFile + "/WEB-INF/tld/liferay-util.tld", true);
395         }
396     }
397 
398     protected void copyXmls(
399             File srcFile, String displayName, PluginPackage pluginPackage)
400         throws Exception {
401 
402         if (appServerType.startsWith(ServerDetector.GERONIMO_ID)) {
403             copyDependencyXml("geronimo-web.xml", srcFile + "/WEB-INF");
404         }
405         else if (appServerType.equals(ServerDetector.WEBLOGIC_ID)) {
406             copyDependencyXml("weblogic.xml", srcFile + "/WEB-INF");
407         }
408         else if (appServerType.equals(ServerDetector.WEBSPHERE_ID)) {
409             copyDependencyXml("ibm-web-ext.xmi", srcFile + "/WEB-INF");
410         }
411 
412         copyDependencyXml("web.xml", srcFile + "/WEB-INF");
413     }
414 
415     protected void deploy() throws Exception {
416         try {
417             File baseDirFile = new File(baseDir);
418 
419             File[] files = baseDirFile.listFiles();
420 
421             if (files == null) {
422                 return;
423             }
424 
425             files = FileUtil.sortFiles(files);
426 
427             for (int i = 0; i < files.length; i++) {
428                 File srcFile = files[i];
429 
430                 String fileName = srcFile.getName().toLowerCase();
431 
432                 boolean deploy = false;
433 
434                 if (fileName.endsWith(".war") || fileName.endsWith(".zip")) {
435                     deploy = true;
436 
437                     if (wars.size() > 0) {
438                         if (!wars.contains(srcFile.getName())) {
439                             deploy = false;
440                         }
441                     }
442                     else if (Validator.isNotNull(filePattern)) {
443                         if (!StringUtil.matches(fileName, filePattern)) {
444                             deploy = false;
445                         }
446                     }
447                 }
448 
449                 if (deploy) {
450                     deployFile(srcFile);
451                 }
452             }
453         }
454         catch (Exception e) {
455             e.printStackTrace();
456         }
457     }
458 
459     protected void deployDirectory(
460             File srcFile, String displayName, boolean override,
461             PluginPackage pluginPackage)
462         throws Exception {
463 
464         deployDirectory(
465             srcFile, null, null, displayName, override, pluginPackage);
466     }
467 
468     protected void deployDirectory(
469             File srcFile, File mergeDir, File deployDir, String displayName,
470             boolean overwrite, PluginPackage pluginPackage)
471         throws Exception {
472 
473         rewriteFiles(srcFile);
474 
475         mergeDirectory(mergeDir, srcFile);
476 
477         processPluginPackageProperties(srcFile, displayName, pluginPackage);
478 
479         copyJars(srcFile, pluginPackage);
480         copyProperties(srcFile, pluginPackage);
481         copyTlds(srcFile, pluginPackage);
482         copyXmls(srcFile, displayName, pluginPackage);
483         copyPortalDependencies(srcFile);
484 
485         updateGeronimoWebXml(srcFile, displayName, pluginPackage);
486 
487         File webXml = new File(srcFile + "/WEB-INF/web.xml");
488 
489         updateWebXml(webXml, srcFile, displayName, pluginPackage);
490 
491         if ((deployDir != null) && !baseDir.equals(destDir)) {
492             updateDeployDirectory(srcFile);
493 
494             String excludes = StringPool.BLANK;
495 
496             if (appServerType.startsWith("jboss")) {
497                 excludes += "**/WEB-INF/lib/log4j.jar,";
498             }
499             else if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
500                 String[] libs = FileUtil.listFiles(tomcatLibDir);
501 
502                 for (int i = 0; i < libs.length; i++) {
503                     excludes += "**/WEB-INF/lib/" + libs[i] + ",";
504                 }
505 
506                 File contextXml = new File(srcFile + "/META-INF/context.xml");
507 
508                 if (contextXml.exists()) {
509                     String content = FileUtil.read(contextXml);
510 
511                     if (content.indexOf(_PORTAL_CLASS_LOADER) != -1) {
512                         excludes += "**/WEB-INF/lib/util-bridges.jar,";
513                         excludes += "**/WEB-INF/lib/util-java.jar,";
514                         excludes += "**/WEB-INF/lib/util-taglib.jar,";
515                     }
516                 }
517 
518                 try {
519 
520                     // LEP-2990
521 
522                     Class.forName("javax.el.ELContext");
523 
524                     excludes += "**/WEB-INF/lib/el-api.jar,";
525                 }
526                 catch (ClassNotFoundException cnfe) {
527                 }
528             }
529 
530             if (!unpackWar ||
531                 appServerType.equals(ServerDetector.WEBSPHERE_ID)) {
532 
533                 File tempDir = new File(
534                     SystemProperties.get(SystemProperties.TMP_DIR) +
535                         File.separator + Time.getTimestamp());
536 
537                 WarTask.war(srcFile, tempDir, "WEB-INF/web.xml", webXml);
538 
539                 if (!tempDir.renameTo(deployDir)) {
540                     WarTask.war(srcFile, deployDir, "WEB-INF/web.xml", webXml);
541                 }
542 
543                 DeleteTask.deleteDirectory(tempDir);
544             }
545             else {
546                 File extLibGlobalDir = new File(
547                     srcFile.getAbsolutePath() + "/WEB-INF/ext-lib/global");
548 
549                 if (extLibGlobalDir.exists()) {
550                     File globalLibDir = new File(PortalUtil.getGlobalLibDir());
551 
552                     CopyTask.copyDirectory(
553                         extLibGlobalDir, globalLibDir, "*.jar",
554                         StringPool.BLANK, overwrite, true);
555                 }
556 
557                 // The deployer might only copy files that have been modified.
558                 // However, the deployer always copies and overwrites web.xml
559                 // after the other files have been copied because application
560                 // servers usually detect that a WAR has been modified based on
561                 // the web.xml time stamp.
562 
563                 excludes += "**/WEB-INF/web.xml";
564 
565                 CopyTask.copyDirectory(
566                     srcFile, deployDir, StringPool.BLANK, excludes, overwrite,
567                     true);
568 
569                 CopyTask.copyDirectory(
570                     srcFile, deployDir, "**/WEB-INF/web.xml", StringPool.BLANK,
571                     true, false);
572 
573                 if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
574 
575                     // See org.apache.catalina.startup.HostConfig to see how
576                     // Tomcat checks to make sure that web.xml was modified 5
577                     // seconds after WEB-INF
578 
579                     File deployWebXml = new File(
580                         deployDir + "/WEB-INF/web.xml");
581 
582                     deployWebXml.setLastModified(
583                         System.currentTimeMillis() + (Time.SECOND * 6));
584                 }
585             }
586         }
587     }
588 
589     protected void deployFile(File srcFile) throws Exception {
590         PluginPackage pluginPackage = readPluginPackage(srcFile);
591 
592         if (_log.isInfoEnabled()) {
593             _log.info("Deploying " + srcFile.getName());
594         }
595 
596         String deployDir = null;
597         String displayName = null;
598         boolean overwrite = false;
599         String preliminaryContext = null;
600 
601         // File names starting with DEPLOY_TO_PREFIX should use the filename
602         // after the prefix as the deployment context
603 
604         if (srcFile.getName().startsWith(DEPLOY_TO_PREFIX)) {
605             displayName = srcFile.getName().substring(
606                 DEPLOY_TO_PREFIX.length(), srcFile.getName().length() - 4);
607 
608             overwrite = true;
609             preliminaryContext = displayName;
610         }
611 
612         if (preliminaryContext == null) {
613             preliminaryContext = getDisplayName(srcFile);
614         }
615 
616         if (pluginPackage != null) {
617             if (!PluginPackageUtil.isCurrentVersionSupported(
618                     pluginPackage.getLiferayVersions())) {
619 
620                 throw new AutoDeployException(
621                     srcFile.getName() +
622                         " does not support this version of Liferay");
623             }
624 
625             if (displayName == null) {
626                 displayName = pluginPackage.getRecommendedDeploymentContext();
627             }
628 
629             if (Validator.isNull(displayName)) {
630                 displayName = getDisplayName(srcFile);
631             }
632 
633             pluginPackage.setContext(displayName);
634 
635             PluginPackageUtil.updateInstallingPluginPackage(
636                 preliminaryContext, pluginPackage);
637         }
638 
639         if (Validator.isNotNull(displayName)) {
640             deployDir = displayName + ".war";
641         }
642         else {
643             deployDir = srcFile.getName();
644             displayName = getDisplayName(srcFile);
645         }
646 
647         if (appServerType.startsWith(ServerDetector.JBOSS_ID)) {
648             deployDir = jbossPrefix + deployDir;
649         }
650         else if (appServerType.equals(ServerDetector.JETTY_ID) ||
651                  appServerType.equals(ServerDetector.OC4J_ID) ||
652                  appServerType.equals(ServerDetector.ORION_ID) ||
653                  appServerType.equals(ServerDetector.RESIN_ID) ||
654                  appServerType.equals(ServerDetector.TOMCAT_ID)) {
655 
656             if (unpackWar) {
657                 deployDir = deployDir.substring(0, deployDir.length() - 4);
658             }
659         }
660 
661         deployDir = destDir + "/" + deployDir;
662 
663         File deployDirFile = new File(deployDir);
664 
665         try {
666             PluginPackage previousPluginPackage =
667                 readPluginPackage(deployDirFile);
668 
669             if ((pluginPackage != null) && (previousPluginPackage != null)) {
670                 if (_log.isInfoEnabled()) {
671                     String name = pluginPackage.getName();
672                     String previousVersion = previousPluginPackage.getVersion();
673                     String version = pluginPackage.getVersion();
674 
675                     _log.info(
676                         "Updating " + name + " from version " +
677                             previousVersion + " to version " + version);
678                 }
679 
680                 if (pluginPackage.isLaterVersionThan(
681                     previousPluginPackage)) {
682 
683                     overwrite = true;
684                 }
685             }
686 
687             File mergeDirFile = new File(
688                 srcFile.getParent() + "/merge/" + srcFile.getName());
689 
690             if (srcFile.isDirectory()) {
691                 deployDirectory(
692                     srcFile, mergeDirFile, deployDirFile, displayName,
693                     overwrite, pluginPackage);
694             }
695             else {
696                 boolean deployed = deployFile(
697                     srcFile, mergeDirFile, deployDirFile, displayName,
698                     overwrite, pluginPackage);
699 
700                 if (!deployed) {
701                     String context = preliminaryContext;
702 
703                     if (pluginPackage != null) {
704                         context = pluginPackage.getContext();
705                     }
706 
707                     PluginPackageUtil.endPluginPackageInstallation(context);
708                 }
709             }
710         }
711         catch (Exception e) {
712             if (pluginPackage != null) {
713                 PluginPackageUtil.endPluginPackageInstallation(
714                     pluginPackage.getContext());
715             }
716 
717             throw e;
718         }
719     }
720 
721     protected boolean deployFile(
722             File srcFile, File mergeDir, File deployDir, String displayName,
723             boolean overwrite, PluginPackage pluginPackage)
724         throws Exception {
725 
726         boolean undeployOnRedeploy = false;
727 
728         try {
729             undeployOnRedeploy = PrefsPropsUtil.getBoolean(
730                 PropsKeys.HOT_UNDEPLOY_ON_REDEPLOY,
731                 PropsValues.HOT_UNDEPLOY_ON_REDEPLOY);
732         }
733         catch (Exception e) {
734 
735             // This will only happen when running the deploy tool in Ant in the
736             // classical way where the WAR file is actually massaged and
737             // packaged.
738 
739         }
740 
741         if (undeployOnRedeploy) {
742             DeployUtil.undeploy(appServerType, deployDir);
743         }
744 
745         if (!overwrite && UpToDateTask.isUpToDate(srcFile, deployDir)) {
746             if (_log.isInfoEnabled()) {
747                 _log.info(deployDir + " is already up to date");
748             }
749 
750             return false;
751         }
752 
753         File tempDir = new File(
754             SystemProperties.get(SystemProperties.TMP_DIR) + File.separator +
755                 Time.getTimestamp());
756 
757         ExpandTask.expand(srcFile, tempDir);
758 
759         deployDirectory(
760             tempDir, mergeDir, deployDir, displayName, overwrite,
761             pluginPackage);
762 
763         DeleteTask.deleteDirectory(tempDir);
764 
765         return true;
766     }
767 
768     protected String downloadJar(String jar) throws Exception {
769         String tmpDir = SystemProperties.get(SystemProperties.TMP_DIR);
770 
771         File file = new File(
772             tmpDir + "/liferay/com/liferay/portal/deploy/dependencies/" +
773                 jar);
774 
775         if (!file.exists()) {
776             synchronized (this) {
777                 String url = PropsUtil.get(
778                     PropsKeys.LIBRARY_DOWNLOAD_URL + jar);
779 
780                 if (_log.isInfoEnabled()) {
781                     _log.info("Downloading library from " + url);
782                 }
783 
784                 byte[] bytes = HttpUtil.URLtoByteArray(url);
785 
786                 FileUtil.write(file, bytes);
787             }
788         }
789 
790         return FileUtil.getAbsolutePath(file);
791     }
792 
793     protected String getDisplayName(File srcFile) {
794         String displayName = srcFile.getName();
795 
796         if (StringUtil.endsWith(displayName, ".war") ||
797             StringUtil.endsWith(displayName, ".xml")) {
798 
799             displayName = displayName.substring(0, displayName.length() - 4);
800         }
801 
802         if (appServerType.startsWith("jboss") &&
803             Validator.isNotNull(jbossPrefix) &&
804             displayName.startsWith(jbossPrefix)) {
805 
806             displayName = displayName.substring(1, displayName.length());
807         }
808 
809         return displayName;
810     }
811 
812     protected String getExtraContent(
813             double webXmlVersion, File srcFile, String displayName)
814         throws Exception {
815 
816         StringBuilder sb = new StringBuilder();
817 
818         sb.append("<display-name>");
819         sb.append(displayName);
820         sb.append("</display-name>");
821 
822         sb.append("<listener>");
823         sb.append("<listener-class>");
824         sb.append("com.liferay.portal.kernel.servlet.");
825         sb.append("SerializableSessionAttributeListener");
826         sb.append("</listener-class>");
827         sb.append("</listener>");
828 
829         File serviceXml = new File(srcFile + "/WEB-INF/service.xml");
830 
831         if (serviceXml.exists()) {
832             sb.append("<listener>");
833             sb.append("<listener-class>");
834             sb.append("com.liferay.portal.kernel.spring.context.");
835             sb.append("PortletContextLoaderListener");
836             sb.append("</listener-class>");
837             sb.append("</listener>");
838         }
839 
840         boolean hasTaglib = false;
841 
842         if (Validator.isNotNull(portletTaglibDTD) ||
843             Validator.isNotNull(portletExtTaglibDTD) ||
844             Validator.isNotNull(securityTaglibDTD) ||
845             Validator.isNotNull(themeTaglibDTD) ||
846             Validator.isNotNull(uiTaglibDTD) ||
847             Validator.isNotNull(utilTaglibDTD)) {
848 
849             hasTaglib = true;
850         }
851 
852         if (hasTaglib && (webXmlVersion > 2.3)) {
853             sb.append("<jsp-config>");
854         }
855 
856         if (Validator.isNotNull(portletTaglibDTD)) {
857             sb.append("<taglib>");
858             sb.append(
859                 "<taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>");
860             sb.append("<taglib-location>");
861             sb.append("/WEB-INF/tld/liferay-portlet.tld");
862             sb.append("</taglib-location>");
863             sb.append("</taglib>");
864         }
865 
866         if (Validator.isNotNull(portletExtTaglibDTD)) {
867             sb.append("<taglib>");
868             sb.append("<taglib-uri>");
869             sb.append("http://liferay.com/tld/portlet");
870             sb.append("</taglib-uri>");
871             sb.append("<taglib-location>");
872             sb.append("/WEB-INF/tld/liferay-portlet-ext.tld");
873             sb.append("</taglib-location>");
874             sb.append("</taglib>");
875         }
876 
877         if (Validator.isNotNull(securityTaglibDTD)) {
878             sb.append("<taglib>");
879             sb.append("<taglib-uri>");
880             sb.append("http://liferay.com/tld/security");
881             sb.append("</taglib-uri>");
882             sb.append("<taglib-location>");
883             sb.append("/WEB-INF/tld/liferay-security.tld");
884             sb.append("</taglib-location>");
885             sb.append("</taglib>");
886         }
887 
888         if (Validator.isNotNull(themeTaglibDTD)) {
889             sb.append("<taglib>");
890             sb.append("<taglib-uri>http://liferay.com/tld/theme</taglib-uri>");
891             sb.append("<taglib-location>");
892             sb.append("/WEB-INF/tld/liferay-theme.tld");
893             sb.append("</taglib-location>");
894             sb.append("</taglib>");
895         }
896 
897         if (Validator.isNotNull(uiTaglibDTD)) {
898             sb.append("<taglib>");
899             sb.append("<taglib-uri>http://liferay.com/tld/ui</taglib-uri>");
900             sb.append("<taglib-location>");
901             sb.append("/WEB-INF/tld/liferay-ui.tld");
902             sb.append("</taglib-location>");
903             sb.append("</taglib>");
904         }
905 
906         if (Validator.isNotNull(utilTaglibDTD)) {
907             sb.append("<taglib>");
908             sb.append("<taglib-uri>http://liferay.com/tld/util</taglib-uri>");
909             sb.append("<taglib-location>");
910             sb.append("/WEB-INF/tld/liferay-util.tld");
911             sb.append("</taglib-location>");
912             sb.append("</taglib>");
913         }
914 
915         if (hasTaglib && (webXmlVersion > 2.3)) {
916             sb.append("</jsp-config>");
917         }
918 
919         return sb.toString();
920     }
921 
922     protected String getPluginPackageLicensesXml(List<License> licenses) {
923         StringBuilder sb = new StringBuilder();
924 
925         for (int i = 0; i < licenses.size(); i++) {
926             License license = licenses.get(i);
927 
928             if (i == 0) {
929                 sb.append("\r\n");
930             }
931 
932             sb.append("\t\t<license osi-approved=\"");
933             sb.append(license.isOsiApproved());
934             sb.append("\">");
935             sb.append(license.getName());
936             sb.append("</license>\r\n");
937 
938             if ((i + 1) == licenses.size()) {
939                 sb.append("\t");
940             }
941         }
942 
943         return sb.toString();
944     }
945 
946     protected String getPluginPackageLiferayVersionsXml(
947         List<String> liferayVersions) {
948 
949         StringBuilder sb = new StringBuilder();
950 
951         for (int i = 0; i < liferayVersions.size(); i++) {
952             String liferayVersion = liferayVersions.get(i);
953 
954             if (i == 0) {
955                 sb.append("\r\n");
956             }
957 
958             sb.append("\t\t<liferay-version>");
959             sb.append(liferayVersion);
960             sb.append("</liferay-version>\r\n");
961 
962             if ((i + 1) == liferayVersions.size()) {
963                 sb.append("\t");
964             }
965         }
966 
967         return sb.toString();
968     }
969 
970     protected Properties getPluginPackageProperties(File srcFile)
971         throws Exception {
972 
973         File propertiesFile = new File(
974             srcFile + "/WEB-INF/liferay-plugin-package.properties");
975 
976         if (!propertiesFile.exists()) {
977             return null;
978         }
979 
980         String propertiesString = FileUtil.read(propertiesFile);
981 
982         return PropertiesUtil.load(propertiesString);
983     }
984 
985     protected String getPluginPackageTagsXml(List<String> tags) {
986         StringBuilder sb = new StringBuilder();
987 
988         for (int i = 0; i < tags.size(); i++) {
989             String tag = tags.get(i);
990 
991             if (i == 0) {
992                 sb.append("\r\n");
993             }
994 
995             sb.append("\t\t<tag>");
996             sb.append(tag);
997             sb.append("</tag>\r\n");
998 
999             if ((i + 1) == tags.size()) {
1000                sb.append("\t");
1001            }
1002        }
1003
1004        return sb.toString();
1005    }
1006
1007    protected String getSpeedFiltersContent(File srcFile) throws Exception {
1008        boolean speedFiltersEnabled = true;
1009
1010        Properties properties = getPluginPackageProperties(srcFile);
1011
1012        if (properties != null) {
1013            speedFiltersEnabled = GetterUtil.getBoolean(
1014                properties.getProperty("speed-filters-enabled"), true);
1015        }
1016
1017        if (speedFiltersEnabled) {
1018            String speedFiltersContent = FileUtil.read(
1019                DeployUtil.getResourcePath("speed_filters.xml"));
1020
1021            return speedFiltersContent;
1022        }
1023        else {
1024            return StringPool.BLANK;
1025        }
1026    }
1027
1028    protected void mergeDirectory(File mergeDir, File targetDir) {
1029        if ((mergeDir == null) || (!mergeDir.exists())) {
1030            return;
1031        }
1032
1033        CopyTask.copyDirectory(mergeDir, targetDir, null, null, true, false);
1034    }
1035
1036    protected void processPluginPackageProperties(
1037            File srcFile, String displayName, PluginPackage pluginPackage)
1038        throws Exception {
1039    }
1040
1041    protected PluginPackage readPluginPackage(File file) {
1042        if (!file.exists()) {
1043            return null;
1044        }
1045
1046        InputStream is = null;
1047        ZipFile zipFile = null;
1048
1049        try {
1050            boolean parseProps = false;
1051
1052            if (file.isDirectory()) {
1053                String path = file.getPath();
1054
1055                File pluginPackageXmlFile = new File(
1056                    file.getParent() + "/merge/" + file.getName() +
1057                        "/WEB-INF/liferay-plugin-package.xml");
1058
1059                if (pluginPackageXmlFile.exists()) {
1060                    is = new FileInputStream(pluginPackageXmlFile);
1061                }
1062                else {
1063                    pluginPackageXmlFile = new File(
1064                        path + "/WEB-INF/liferay-plugin-package.xml");
1065
1066                    if (pluginPackageXmlFile.exists()) {
1067                        is = new FileInputStream(pluginPackageXmlFile);
1068                    }
1069                }
1070
1071                File pluginPackagePropsFile = new File(
1072                    file.getParent() + "/merge/" + file.getName() +
1073                        "/WEB-INF/liferay-plugin-package.properties");
1074
1075                if ((is == null) && pluginPackagePropsFile.exists()) {
1076                    is = new FileInputStream(pluginPackagePropsFile);
1077
1078                    parseProps = true;
1079                }
1080                else {
1081                    pluginPackagePropsFile = new File(
1082                        path + "/WEB-INF/liferay-plugin-package.properties");
1083
1084                    if ((is == null) && pluginPackagePropsFile.exists()) {
1085                        is = new FileInputStream(pluginPackagePropsFile);
1086
1087                        parseProps = true;
1088                    }
1089                }
1090            }
1091            else {
1092                zipFile = new ZipFile(file);
1093
1094                File pluginPackageXmlFile = new File(
1095                    file.getParent() + "/merge/" + file.getName() +
1096                        "/WEB-INF/liferay-plugin-package.xml");
1097
1098                if (pluginPackageXmlFile.exists()) {
1099                    is = new FileInputStream(pluginPackageXmlFile);
1100                }
1101                else {
1102                    ZipEntry zipEntry = zipFile.getEntry(
1103                        "WEB-INF/liferay-plugin-package.xml");
1104
1105                    if (zipEntry != null) {
1106                        is = zipFile.getInputStream(zipEntry);
1107                    }
1108                }
1109
1110                File pluginPackagePropsFile = new File(
1111                    file.getParent() + "/merge/" + file.getName() +
1112                        "/WEB-INF/liferay-plugin-package.properties");
1113
1114                if ((is == null) && pluginPackagePropsFile.exists()) {
1115                    is = new FileInputStream(pluginPackagePropsFile);
1116
1117                    parseProps = true;
1118                }
1119                else {
1120                    ZipEntry zipEntry = zipFile.getEntry(
1121                        "WEB-INF/liferay-plugin-package.properties");
1122
1123                    if ((is == null) && (zipEntry != null)) {
1124                        is = zipFile.getInputStream(zipEntry);
1125
1126                        parseProps = true;
1127                    }
1128                }
1129            }
1130
1131            if (is == null) {
1132                if (_log.isInfoEnabled()) {
1133                    _log.info(
1134                        file.getPath() + " does not have a " +
1135                            "WEB-INF/liferay-plugin-package.xml or " +
1136                                "WEB-INF/liferay-plugin-package.properties");
1137                }
1138
1139                return null;
1140            }
1141
1142            if (parseProps) {
1143                String displayName = getDisplayName(file);
1144
1145                String propertiesString = StringUtil.read(is);
1146
1147                Properties properties = PropertiesUtil.load(propertiesString);
1148
1149                return PluginPackageUtil.readPluginPackageProps(
1150                    displayName, properties);
1151            }
1152            else {
1153                String xml = StringUtil.read(is);
1154
1155                xml = XMLFormatter.fixProlog(xml);
1156
1157                return PluginPackageUtil.readPluginPackageXml(xml);
1158            }
1159        }
1160        catch (Exception e) {
1161            _log.error(file.getPath() + ": " + e.toString());
1162        }
1163        finally {
1164            if (is != null) {
1165                try {
1166                    is.close();
1167                }
1168                catch (IOException ioe) {
1169                }
1170            }
1171
1172            if (zipFile != null) {
1173                try {
1174                    zipFile.close();
1175                }
1176                catch (IOException ioe) {
1177                }
1178            }
1179        }
1180
1181        return null;
1182    }
1183
1184    protected void rewriteFiles(File srcDir) throws Exception {
1185        String[] files = FileUtil.listFiles(srcDir + "/WEB-INF/");
1186
1187        for (int i = 0; i < files.length; i++) {
1188            String fileName = GetterUtil.getString(
1189                FileUtil.getShortFileName(files[i]));
1190
1191            // LEP-6415
1192
1193            if (fileName.equalsIgnoreCase("mule-config.xml")) {
1194                continue;
1195            }
1196
1197            String ext = GetterUtil.getString(FileUtil.getExtension(files[i]));
1198
1199            if (!ext.equalsIgnoreCase("xml")) {
1200                continue;
1201            }
1202
1203            // Make sure to rewrite any XML files to include external entities
1204            // into same file. See LEP-3142.
1205
1206            File file = new File(srcDir + "/WEB-INF/" + files[i]);
1207
1208            try {
1209                Document doc = SAXReaderUtil.read(file);
1210
1211                String content = doc.formattedString(StringPool.TAB, true);
1212
1213                FileUtil.write(file, content);
1214            }
1215            catch (Exception e) {
1216                if (_log.isWarnEnabled()) {
1217                    _log.warn(
1218                        "Unable to format " + file + ": " + e.getMessage());
1219                }
1220            }
1221        }
1222    }
1223
1224    protected void updateDeployDirectory(File srcFile) throws Exception {
1225    }
1226
1227    protected void updateGeronimoWebXml(
1228            File srcFile, String displayName, PluginPackage pluginPackage)
1229        throws Exception {
1230
1231        if (!appServerType.startsWith(ServerDetector.GERONIMO_ID)) {
1232            return;
1233        }
1234
1235        File geronimoWebXml = new File(srcFile + "/WEB-INF/geronimo-web.xml");
1236
1237        Document doc = SAXReaderUtil.read(geronimoWebXml);
1238
1239        Element root = doc.getRootElement();
1240
1241        Element environmentEl = root.element("environment");
1242
1243        Element moduleIdEl = environmentEl.element("moduleId");
1244
1245        Element artifactIdEl = moduleIdEl.element("artifactId");
1246
1247        String artifactIdText = GetterUtil.getString(artifactIdEl.getText());
1248
1249        if (!artifactIdText.equals(displayName)) {
1250            artifactIdEl.setText(displayName);
1251
1252            String content = doc.formattedString();
1253
1254            FileUtil.write(geronimoWebXml, content);
1255
1256            if (_log.isInfoEnabled()) {
1257                _log.info("Modifying Geronimo " + geronimoWebXml);
1258            }
1259        }
1260    }
1261
1262    protected void updateWebXml(
1263            File webXml, File srcFile, String displayName,
1264            PluginPackage pluginPackage)
1265        throws Exception {
1266
1267        String content = FileUtil.read(webXml);
1268
1269        int x = content.indexOf("<display-name>");
1270
1271        if (x != -1) {
1272            int y = content.indexOf("</display-name>", x);
1273
1274            y = content.indexOf(">", y) + 1;
1275
1276            content = content.substring(0, x) + content.substring(y);
1277        }
1278
1279        double webXmlVersion = 2.3;
1280
1281        Document webXmlDoc = SAXReaderUtil.read(content);
1282
1283        Element webXmlRoot = webXmlDoc.getRootElement();
1284
1285        webXmlVersion = GetterUtil.getDouble(
1286            webXmlRoot.attributeValue("version"), webXmlVersion);
1287
1288        // Merge extra content
1289
1290        String extraContent = getExtraContent(
1291            webXmlVersion, srcFile, displayName);
1292
1293        if (webXmlVersion > 2.3) {
1294            while (true) {
1295                int pos = extraContent.indexOf(
1296                    "<param-name>servlet-2.4-dispatcher</param-name>");
1297
1298                if (pos == -1) {
1299                    break;
1300                }
1301
1302                x = extraContent.lastIndexOf("<init-param>", pos);
1303                int y = extraContent.indexOf("</init-param>", pos);
1304
1305                extraContent =
1306                    extraContent.substring(0, x) +
1307                        extraContent.substring(y + 13);
1308            }
1309        }
1310
1311        int pos = content.indexOf("</web-app>");
1312
1313        String newContent =
1314            content.substring(0, pos) + extraContent +
1315            content.substring(pos, content.length());
1316
1317        // Replace old package names
1318
1319        newContent = StringUtil.replace(
1320            newContent, "com.liferay.portal.shared.",
1321            "com.liferay.portal.kernel.");
1322
1323        newContent = WebXMLBuilder.organizeWebXML(newContent);
1324
1325        FileUtil.write(webXml, newContent, true);
1326
1327        if (_log.isInfoEnabled()) {
1328            _log.info("Modifying Servlet " + webXmlVersion + " " + webXml);
1329        }
1330    }
1331
1332    protected String baseDir;
1333    protected String destDir;
1334    protected String appServerType;
1335    protected String portletTaglibDTD;
1336    protected String portletExtTaglibDTD;
1337    protected String securityTaglibDTD;
1338    protected String themeTaglibDTD;
1339    protected String uiTaglibDTD;
1340    protected String utilTaglibDTD;
1341    protected boolean unpackWar;
1342    protected String filePattern;
1343    protected String jbossPrefix;
1344    protected String tomcatLibDir;
1345    protected List<String> wars;
1346    protected List<String> jars;
1347
1348    private static final String _PORTAL_CLASS_LOADER =
1349        "com.liferay.support.tomcat.loader.PortalClassLoader";
1350
1351    private static Log _log = LogFactoryUtil.getLog(BaseDeployer.class);
1352
1353}