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