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.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         portletTaglibDTD = System.getProperty("deployer.portlet.taglib.dtd");
106         portletExtTaglibDTD = System.getProperty(
107             "deployer.portlet.ext.taglib.dtd");
108         securityTaglibDTD = System.getProperty("deployer.security.taglib.dtd");
109         themeTaglibDTD = System.getProperty("deployer.theme.taglib.dtd");
110         uiTaglibDTD = System.getProperty("deployer.ui.taglib.dtd");
111         utilTaglibDTD = System.getProperty("deployer.util.taglib.dtd");
112         unpackWar = GetterUtil.getBoolean(
113             System.getProperty("deployer.unpack.war"), true);
114         filePattern = System.getProperty("deployer.file.pattern");
115         jbossPrefix = GetterUtil.getString(
116             System.getProperty("deployer.jboss.prefix"));
117         tomcatLibDir = System.getProperty("deployer.tomcat.lib.dir");
118         this.wars = wars;
119         this.jars = jars;
120 
121         checkArguments();
122 
123         try {
124             deploy();
125         }
126         catch (Exception e) {
127             e.printStackTrace();
128         }
129     }
130 
131     protected void addExtJar(List<String> jars, String resource)
132         throws Exception {
133 
134         Set<String> servletContextNames = ExtRegistry.getServletContextNames();
135 
136         for (String servletContextName : servletContextNames) {
137             String extResource =
138                 "ext-" + servletContextName + resource.substring(3);
139 
140             String path = DeployUtil.getResourcePath(extResource);
141 
142             if (_log.isDebugEnabled()) {
143                 if (path == null) {
144                     _log.debug("Resource " + extResource + " is not available");
145                 }
146                 else {
147                     _log.debug(
148                         "Resource " + extResource + " is available at " + path);
149                 }
150             }
151 
152             if (path != null) {
153                 jars.add(path);
154             }
155         }
156     }
157 
158     protected void addRequiredJar(List<String> jars, String resource)
159         throws Exception {
160 
161         String path = DeployUtil.getResourcePath(resource);
162 
163         if (path == null) {
164             throw new RuntimeException(
165                 "Resource " + resource + " does not exist");
166         }
167 
168         if (_log.isDebugEnabled()) {
169             _log.debug("Resource " + resource + " is available at " + path);
170         }
171 
172         jars.add(path);
173     }
174 
175     protected void checkArguments() {
176         if (Validator.isNull(baseDir)) {
177             throw new IllegalArgumentException(
178                 "The system property deployer.base.dir is not set");
179         }
180 
181         if (Validator.isNull(destDir)) {
182             throw new IllegalArgumentException(
183                 "The system property deployer.dest.dir is not set");
184         }
185 
186         if (Validator.isNull(appServerType)) {
187             throw new IllegalArgumentException(
188                 "The system property deployer.app.server.type is not set");
189         }
190 
191         if (!appServerType.startsWith(ServerDetector.GERONIMO_ID) &&
192             !appServerType.startsWith(ServerDetector.GLASSFISH_ID) &&
193             !appServerType.startsWith(ServerDetector.JBOSS_ID) &&
194             !appServerType.startsWith(ServerDetector.JONAS_ID) &&
195             !appServerType.equals(ServerDetector.JETTY_ID) &&
196             !appServerType.equals(ServerDetector.OC4J_ID) &&
197             !appServerType.equals(ServerDetector.RESIN_ID) &&
198             !appServerType.equals(ServerDetector.TOMCAT_ID) &&
199             !appServerType.equals(ServerDetector.WEBLOGIC_ID) &&
200             !appServerType.equals(ServerDetector.WEBSPHERE_ID)) {
201 
202             throw new IllegalArgumentException(
203                 appServerType + " is not a valid application server type");
204         }
205 
206         if (appServerType.startsWith(ServerDetector.GLASSFISH_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             return;
493         }
494 
495         updateDeployDirectory(srcFile);
496 
497         String excludes = StringPool.BLANK;
498 
499         if (appServerType.startsWith("jboss")) {
500             excludes += "**/WEB-INF/lib/log4j.jar,";
501         }
502         else if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
503             String[] libs = FileUtil.listFiles(tomcatLibDir);
504 
505             for (int i = 0; i < libs.length; i++) {
506                 excludes += "**/WEB-INF/lib/" + libs[i] + ",";
507             }
508 
509             File contextXml = new File(srcFile + "/META-INF/context.xml");
510 
511             if (contextXml.exists()) {
512                 String content = FileUtil.read(contextXml);
513 
514                 if (content.indexOf(_PORTAL_CLASS_LOADER) != -1) {
515                     excludes += "**/WEB-INF/lib/util-bridges.jar,";
516                     excludes += "**/WEB-INF/lib/util-java.jar,";
517                     excludes += "**/WEB-INF/lib/util-taglib.jar,";
518                 }
519             }
520 
521             try {
522 
523                 // LEP-2990
524 
525                 Class.forName("javax.el.ELContext");
526 
527                 excludes += "**/WEB-INF/lib/el-api.jar,";
528             }
529             catch (ClassNotFoundException cnfe) {
530             }
531         }
532 
533         if (!unpackWar || appServerType.equals(ServerDetector.WEBSPHERE_ID)) {
534             File tempDir = new File(
535                 SystemProperties.get(SystemProperties.TMP_DIR) +
536                     File.separator + Time.getTimestamp());
537 
538             WarTask.war(srcFile, tempDir, "WEB-INF/web.xml", webXml);
539 
540             if (isJEEDeploymentEnabled()) {
541                 File tempWarDir = new File(
542                     tempDir.getParent(), deployDir.getName());
543 
544                 if (tempWarDir.exists()) {
545                     tempWarDir.delete();
546                 }
547 
548                 if (!tempDir.renameTo(tempWarDir)) {
549                     tempWarDir = tempDir;
550                 }
551 
552                 DeploymentHandler deploymentHandler = getDeploymentHandler();
553 
554                 deploymentHandler.deploy(tempWarDir, displayName);
555 
556                 deploymentHandler.releaseDeploymentManager();
557 
558                 DeleteTask.deleteDirectory(tempWarDir);
559             }
560             else {
561                 if (!tempDir.renameTo(deployDir)) {
562                     WarTask.war(srcFile, deployDir, "WEB-INF/web.xml", webXml);
563                 }
564 
565                 DeleteTask.deleteDirectory(tempDir);
566             }
567         }
568         else {
569             File extLibGlobalDir = new File(
570                 srcFile.getAbsolutePath() + "/WEB-INF/ext-lib/global");
571 
572             if (extLibGlobalDir.exists()) {
573                 File globalLibDir = new File(PortalUtil.getGlobalLibDir());
574 
575                 CopyTask.copyDirectory(
576                     extLibGlobalDir, globalLibDir, "*.jar", StringPool.BLANK,
577                     overwrite, true);
578             }
579 
580             // The deployer might only copy files that have been modified.
581             // However, the deployer always copies and overwrites web.xml after
582             // the other files have been copied because application servers
583             // usually detect that a WAR has been modified based on the web.xml
584             // timestamp.
585 
586             excludes += "**/WEB-INF/web.xml";
587 
588             CopyTask.copyDirectory(
589                 srcFile, deployDir, StringPool.BLANK, excludes, overwrite,
590                 true);
591 
592             CopyTask.copyDirectory(
593                 srcFile, deployDir, "**/WEB-INF/web.xml", StringPool.BLANK,
594                 true, false);
595 
596             if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
597 
598                 // See org.apache.catalina.startup.HostConfig to see how Tomcat
599                 // checks to make sure that web.xml was modified 5 seconds after
600                 // WEB-INF
601 
602                 File deployWebXml = new File(deployDir + "/WEB-INF/web.xml");
603 
604                 deployWebXml.setLastModified(
605                     System.currentTimeMillis() + (Time.SECOND * 6));
606             }
607         }
608     }
609 
610     protected void deployFile(File srcFile) throws Exception {
611         PluginPackage pluginPackage = readPluginPackage(srcFile);
612 
613         if (_log.isInfoEnabled()) {
614             _log.info("Deploying " + srcFile.getName());
615         }
616 
617         String deployDir = null;
618         String displayName = null;
619         boolean overwrite = false;
620         String preliminaryContext = null;
621 
622         // File names starting with DEPLOY_TO_PREFIX should use the filename
623         // after the prefix as the deployment context
624 
625         if (srcFile.getName().startsWith(DEPLOY_TO_PREFIX)) {
626             displayName = srcFile.getName().substring(
627                 DEPLOY_TO_PREFIX.length(), srcFile.getName().length() - 4);
628 
629             overwrite = true;
630             preliminaryContext = displayName;
631         }
632 
633         if (preliminaryContext == null) {
634             preliminaryContext = getDisplayName(srcFile);
635         }
636 
637         if (pluginPackage != null) {
638             if (!PluginPackageUtil.isCurrentVersionSupported(
639                     pluginPackage.getLiferayVersions())) {
640 
641                 throw new AutoDeployException(
642                     srcFile.getName() +
643                         " does not support this version of Liferay");
644             }
645 
646             if (displayName == null) {
647                 displayName = pluginPackage.getRecommendedDeploymentContext();
648             }
649 
650             if (Validator.isNull(displayName)) {
651                 displayName = getDisplayName(srcFile);
652             }
653 
654             pluginPackage.setContext(displayName);
655 
656             PluginPackageUtil.updateInstallingPluginPackage(
657                 preliminaryContext, pluginPackage);
658         }
659 
660         if (Validator.isNotNull(displayName)) {
661             deployDir = displayName + ".war";
662         }
663         else {
664             deployDir = srcFile.getName();
665             displayName = getDisplayName(srcFile);
666         }
667 
668         if (appServerType.startsWith(ServerDetector.JBOSS_ID)) {
669             deployDir = jbossPrefix + deployDir;
670         }
671         else if (appServerType.equals(ServerDetector.JETTY_ID) ||
672                  appServerType.equals(ServerDetector.OC4J_ID) ||
673                  appServerType.equals(ServerDetector.RESIN_ID) ||
674                  appServerType.equals(ServerDetector.TOMCAT_ID)) {
675 
676             if (unpackWar) {
677                 deployDir = deployDir.substring(0, deployDir.length() - 4);
678             }
679         }
680 
681         deployDir = destDir + "/" + deployDir;
682 
683         File deployDirFile = new File(deployDir);
684 
685         try {
686             PluginPackage previousPluginPackage =
687                 readPluginPackage(deployDirFile);
688 
689             if ((pluginPackage != null) && (previousPluginPackage != null)) {
690                 if (_log.isInfoEnabled()) {
691                     String name = pluginPackage.getName();
692                     String previousVersion = previousPluginPackage.getVersion();
693                     String version = pluginPackage.getVersion();
694 
695                     _log.info(
696                         "Updating " + name + " from version " +
697                             previousVersion + " to version " + version);
698                 }
699 
700                 if (pluginPackage.isLaterVersionThan(
701                     previousPluginPackage)) {
702 
703                     overwrite = true;
704                 }
705             }
706 
707             File mergeDirFile = new File(
708                 srcFile.getParent() + "/merge/" + srcFile.getName());
709 
710             if (srcFile.isDirectory()) {
711                 deployDirectory(
712                     srcFile, mergeDirFile, deployDirFile, displayName,
713                     overwrite, pluginPackage);
714             }
715             else {
716                 boolean deployed = deployFile(
717                     srcFile, mergeDirFile, deployDirFile, displayName,
718                     overwrite, pluginPackage);
719 
720                 if (!deployed) {
721                     String context = preliminaryContext;
722 
723                     if (pluginPackage != null) {
724                         context = pluginPackage.getContext();
725                     }
726 
727                     PluginPackageUtil.endPluginPackageInstallation(context);
728                 }
729             }
730         }
731         catch (Exception e) {
732             if (pluginPackage != null) {
733                 PluginPackageUtil.endPluginPackageInstallation(
734                     pluginPackage.getContext());
735             }
736 
737             throw e;
738         }
739     }
740 
741     protected boolean deployFile(
742             File srcFile, File mergeDir, File deployDir, String displayName,
743             boolean overwrite, PluginPackage pluginPackage)
744         throws Exception {
745 
746         boolean undeployOnRedeploy = false;
747 
748         try {
749             undeployOnRedeploy = PrefsPropsUtil.getBoolean(
750                 PropsKeys.HOT_UNDEPLOY_ON_REDEPLOY,
751                 PropsValues.HOT_UNDEPLOY_ON_REDEPLOY);
752         }
753         catch (Exception e) {
754 
755             // This will only happen when running the deploy tool in Ant in the
756             // classical way where the WAR file is actually massaged and
757             // packaged.
758 
759         }
760 
761         if (undeployOnRedeploy) {
762             DeployUtil.undeploy(appServerType, deployDir);
763         }
764 
765         if (!overwrite && UpToDateTask.isUpToDate(srcFile, deployDir)) {
766             if (_log.isInfoEnabled()) {
767                 _log.info(deployDir + " is already up to date");
768             }
769 
770             return false;
771         }
772 
773         File tempDir = new File(
774             SystemProperties.get(SystemProperties.TMP_DIR) + File.separator +
775                 Time.getTimestamp());
776 
777         ExpandTask.expand(srcFile, tempDir);
778 
779         deployDirectory(
780             tempDir, mergeDir, deployDir, displayName, overwrite,
781             pluginPackage);
782 
783         DeleteTask.deleteDirectory(tempDir);
784 
785         return true;
786     }
787 
788     protected String downloadJar(String jar) throws Exception {
789         String tmpDir = SystemProperties.get(SystemProperties.TMP_DIR);
790 
791         File file = new File(
792             tmpDir + "/liferay/com/liferay/portal/deploy/dependencies/" +
793                 jar);
794 
795         if (!file.exists()) {
796             synchronized (this) {
797                 String url = PropsUtil.get(
798                     PropsKeys.LIBRARY_DOWNLOAD_URL + jar);
799 
800                 if (_log.isInfoEnabled()) {
801                     _log.info("Downloading library from " + url);
802                 }
803 
804                 byte[] bytes = HttpUtil.URLtoByteArray(url);
805 
806                 FileUtil.write(file, bytes);
807             }
808         }
809 
810         return FileUtil.getAbsolutePath(file);
811     }
812 
813     protected String getDisplayName(File srcFile) {
814         String displayName = srcFile.getName();
815 
816         if (StringUtil.endsWith(displayName, ".war") ||
817             StringUtil.endsWith(displayName, ".xml")) {
818 
819             displayName = displayName.substring(0, displayName.length() - 4);
820         }
821 
822         if (appServerType.startsWith("jboss") &&
823             Validator.isNotNull(jbossPrefix) &&
824             displayName.startsWith(jbossPrefix)) {
825 
826             displayName = displayName.substring(1, displayName.length());
827         }
828 
829         return displayName;
830     }
831 
832     protected DeploymentHandler getDeploymentHandler() {
833         String prefix = "auto.deploy." + ServerDetector.getServerId() + ".jee.";
834 
835         String dmId = PropsUtil.get(prefix + "dm.id");
836         String dmUser =  PropsUtil.get(prefix + "dm.user");
837         String dmPassword =  PropsUtil.get(prefix + "dm.passwd");
838         String dfClassName = PropsUtil.get(prefix + "df.classname");
839 
840         return new DeploymentHandler(dmId, dmUser, dmPassword, dfClassName);
841     }
842 
843     protected String getExtraContent(
844             double webXmlVersion, File srcFile, String displayName)
845         throws Exception {
846 
847         StringBundler sb = new StringBundler();
848 
849         sb.append("<display-name>");
850         sb.append(displayName);
851         sb.append("</display-name>");
852 
853         sb.append("<listener>");
854         sb.append("<listener-class>");
855         sb.append("com.liferay.portal.kernel.servlet.");
856         sb.append("SerializableSessionAttributeListener");
857         sb.append("</listener-class>");
858         sb.append("</listener>");
859 
860         File serviceXml = new File(srcFile + "/WEB-INF/service.xml");
861 
862         if (serviceXml.exists()) {
863             sb.append("<listener>");
864             sb.append("<listener-class>");
865             sb.append("com.liferay.portal.kernel.spring.context.");
866             sb.append("PortletContextLoaderListener");
867             sb.append("</listener-class>");
868             sb.append("</listener>");
869         }
870 
871         boolean hasTaglib = false;
872 
873         if (Validator.isNotNull(portletTaglibDTD) ||
874             Validator.isNotNull(portletExtTaglibDTD) ||
875             Validator.isNotNull(securityTaglibDTD) ||
876             Validator.isNotNull(themeTaglibDTD) ||
877             Validator.isNotNull(uiTaglibDTD) ||
878             Validator.isNotNull(utilTaglibDTD)) {
879 
880             hasTaglib = true;
881         }
882 
883         if (hasTaglib && (webXmlVersion > 2.3)) {
884             sb.append("<jsp-config>");
885         }
886 
887         if (Validator.isNotNull(portletTaglibDTD)) {
888             sb.append("<taglib>");
889             sb.append(
890                 "<taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>");
891             sb.append("<taglib-location>");
892             sb.append("/WEB-INF/tld/liferay-portlet.tld");
893             sb.append("</taglib-location>");
894             sb.append("</taglib>");
895         }
896 
897         if (Validator.isNotNull(portletExtTaglibDTD)) {
898             sb.append("<taglib>");
899             sb.append("<taglib-uri>");
900             sb.append("http://liferay.com/tld/portlet");
901             sb.append("</taglib-uri>");
902             sb.append("<taglib-location>");
903             sb.append("/WEB-INF/tld/liferay-portlet-ext.tld");
904             sb.append("</taglib-location>");
905             sb.append("</taglib>");
906         }
907 
908         if (Validator.isNotNull(securityTaglibDTD)) {
909             sb.append("<taglib>");
910             sb.append("<taglib-uri>");
911             sb.append("http://liferay.com/tld/security");
912             sb.append("</taglib-uri>");
913             sb.append("<taglib-location>");
914             sb.append("/WEB-INF/tld/liferay-security.tld");
915             sb.append("</taglib-location>");
916             sb.append("</taglib>");
917         }
918 
919         if (Validator.isNotNull(themeTaglibDTD)) {
920             sb.append("<taglib>");
921             sb.append("<taglib-uri>http://liferay.com/tld/theme</taglib-uri>");
922             sb.append("<taglib-location>");
923             sb.append("/WEB-INF/tld/liferay-theme.tld");
924             sb.append("</taglib-location>");
925             sb.append("</taglib>");
926         }
927 
928         if (Validator.isNotNull(uiTaglibDTD)) {
929             sb.append("<taglib>");
930             sb.append("<taglib-uri>http://liferay.com/tld/ui</taglib-uri>");
931             sb.append("<taglib-location>");
932             sb.append("/WEB-INF/tld/liferay-ui.tld");
933             sb.append("</taglib-location>");
934             sb.append("</taglib>");
935         }
936 
937         if (Validator.isNotNull(utilTaglibDTD)) {
938             sb.append("<taglib>");
939             sb.append("<taglib-uri>http://liferay.com/tld/util</taglib-uri>");
940             sb.append("<taglib-location>");
941             sb.append("/WEB-INF/tld/liferay-util.tld");
942             sb.append("</taglib-location>");
943             sb.append("</taglib>");
944         }
945 
946         if (hasTaglib && (webXmlVersion > 2.3)) {
947             sb.append("</jsp-config>");
948         }
949 
950         return sb.toString();
951     }
952 
953     protected String getPluginPackageLicensesXml(List<License> licenses) {
954         if (licenses.isEmpty()) {
955             return StringPool.BLANK;
956         }
957 
958         StringBundler sb = new StringBundler(5 * licenses.size() + 2);
959 
960         for (int i = 0; i < licenses.size(); i++) {
961             License license = licenses.get(i);
962 
963             if (i == 0) {
964                 sb.append("\r\n");
965             }
966 
967             sb.append("\t\t<license osi-approved=\"");
968             sb.append(license.isOsiApproved());
969             sb.append("\">");
970             sb.append(license.getName());
971             sb.append("</license>\r\n");
972 
973             if ((i + 1) == licenses.size()) {
974                 sb.append("\t");
975             }
976         }
977 
978         return sb.toString();
979     }
980 
981     protected String getPluginPackageLiferayVersionsXml(
982         List<String> liferayVersions) {
983 
984         if (liferayVersions.isEmpty()) {
985             return StringPool.BLANK;
986         }
987 
988         StringBundler sb = new StringBundler(liferayVersions.size() * 3 + 2);
989 
990         for (int i = 0; i < liferayVersions.size(); i++) {
991             String liferayVersion = liferayVersions.get(i);
992 
993             if (i == 0) {
994                 sb.append("\r\n");
995             }
996 
997             sb.append("\t\t<liferay-version>");
998             sb.append(liferayVersion);
999             sb.append("</liferay-version>\r\n");
1000
1001            if ((i + 1) == liferayVersions.size()) {
1002                sb.append("\t");
1003            }
1004        }
1005
1006        return sb.toString();
1007    }
1008
1009    protected Properties getPluginPackageProperties(File srcFile)
1010        throws Exception {
1011
1012        File propertiesFile = new File(
1013            srcFile + "/WEB-INF/liferay-plugin-package.properties");
1014
1015        if (!propertiesFile.exists()) {
1016            return null;
1017        }
1018
1019        String propertiesString = FileUtil.read(propertiesFile);
1020
1021        return PropertiesUtil.load(propertiesString);
1022    }
1023
1024    protected String getPluginPackageTagsXml(List<String> tags) {
1025        if (tags.isEmpty()) {
1026            return StringPool.BLANK;
1027        }
1028
1029        StringBundler sb = new StringBundler(tags.size() * 3 + 2);
1030
1031        for (int i = 0; i < tags.size(); i++) {
1032            String tag = tags.get(i);
1033
1034            if (i == 0) {
1035                sb.append("\r\n");
1036            }
1037
1038            sb.append("\t\t<tag>");
1039            sb.append(tag);
1040            sb.append("</tag>\r\n");
1041
1042            if ((i + 1) == tags.size()) {
1043                sb.append("\t");
1044            }
1045        }
1046
1047        return sb.toString();
1048    }
1049
1050    protected String getSpeedFiltersContent(File srcFile) throws Exception {
1051        boolean speedFiltersEnabled = true;
1052
1053        Properties properties = getPluginPackageProperties(srcFile);
1054
1055        if (properties != null) {
1056            speedFiltersEnabled = GetterUtil.getBoolean(
1057                properties.getProperty("speed-filters-enabled"), true);
1058        }
1059
1060        if (speedFiltersEnabled) {
1061            String speedFiltersContent = FileUtil.read(
1062                DeployUtil.getResourcePath("speed_filters.xml"));
1063
1064            return speedFiltersContent;
1065        }
1066        else {
1067            return StringPool.BLANK;
1068        }
1069    }
1070
1071    protected boolean isJEEDeploymentEnabled() {
1072        return GetterUtil.getBoolean(PropsUtil.get(
1073            "auto.deploy." + ServerDetector.getServerId() +
1074                ".jee.deployment.enabled"));
1075    }
1076
1077    protected void mergeDirectory(File mergeDir, File targetDir) {
1078        if ((mergeDir == null) || (!mergeDir.exists())) {
1079            return;
1080        }
1081
1082        CopyTask.copyDirectory(mergeDir, targetDir, null, null, true, false);
1083    }
1084
1085    protected void processPluginPackageProperties(
1086            File srcFile, String displayName, PluginPackage pluginPackage)
1087        throws Exception {
1088    }
1089
1090    protected PluginPackage readPluginPackage(File file) {
1091        if (!file.exists()) {
1092            return null;
1093        }
1094
1095        InputStream is = null;
1096        ZipFile zipFile = null;
1097
1098        try {
1099            boolean parseProps = false;
1100
1101            if (file.isDirectory()) {
1102                String path = file.getPath();
1103
1104                File pluginPackageXmlFile = new File(
1105                    file.getParent() + "/merge/" + file.getName() +
1106                        "/WEB-INF/liferay-plugin-package.xml");
1107
1108                if (pluginPackageXmlFile.exists()) {
1109                    is = new FileInputStream(pluginPackageXmlFile);
1110                }
1111                else {
1112                    pluginPackageXmlFile = new File(
1113                        path + "/WEB-INF/liferay-plugin-package.xml");
1114
1115                    if (pluginPackageXmlFile.exists()) {
1116                        is = new FileInputStream(pluginPackageXmlFile);
1117                    }
1118                }
1119
1120                File pluginPackagePropsFile = new File(
1121                    file.getParent() + "/merge/" + file.getName() +
1122                        "/WEB-INF/liferay-plugin-package.properties");
1123
1124                if ((is == null) && pluginPackagePropsFile.exists()) {
1125                    is = new FileInputStream(pluginPackagePropsFile);
1126
1127                    parseProps = true;
1128                }
1129                else {
1130                    pluginPackagePropsFile = new File(
1131                        path + "/WEB-INF/liferay-plugin-package.properties");
1132
1133                    if ((is == null) && pluginPackagePropsFile.exists()) {
1134                        is = new FileInputStream(pluginPackagePropsFile);
1135
1136                        parseProps = true;
1137                    }
1138                }
1139            }
1140            else {
1141                zipFile = new ZipFile(file);
1142
1143                File pluginPackageXmlFile = new File(
1144                    file.getParent() + "/merge/" + file.getName() +
1145                        "/WEB-INF/liferay-plugin-package.xml");
1146
1147                if (pluginPackageXmlFile.exists()) {
1148                    is = new FileInputStream(pluginPackageXmlFile);
1149                }
1150                else {
1151                    ZipEntry zipEntry = zipFile.getEntry(
1152                        "WEB-INF/liferay-plugin-package.xml");
1153
1154                    if (zipEntry != null) {
1155                        is = zipFile.getInputStream(zipEntry);
1156                    }
1157                }
1158
1159                File pluginPackagePropsFile = new File(
1160                    file.getParent() + "/merge/" + file.getName() +
1161                        "/WEB-INF/liferay-plugin-package.properties");
1162
1163                if ((is == null) && pluginPackagePropsFile.exists()) {
1164                    is = new FileInputStream(pluginPackagePropsFile);
1165
1166                    parseProps = true;
1167                }
1168                else {
1169                    ZipEntry zipEntry = zipFile.getEntry(
1170                        "WEB-INF/liferay-plugin-package.properties");
1171
1172                    if ((is == null) && (zipEntry != null)) {
1173                        is = zipFile.getInputStream(zipEntry);
1174
1175                        parseProps = true;
1176                    }
1177                }
1178            }
1179
1180            if (is == null) {
1181                if (_log.isInfoEnabled()) {
1182                    _log.info(
1183                        file.getPath() + " does not have a " +
1184                            "WEB-INF/liferay-plugin-package.xml or " +
1185                                "WEB-INF/liferay-plugin-package.properties");
1186                }
1187
1188                return null;
1189            }
1190
1191            if (parseProps) {
1192                String displayName = getDisplayName(file);
1193
1194                String propertiesString = StringUtil.read(is);
1195
1196                Properties properties = PropertiesUtil.load(propertiesString);
1197
1198                return PluginPackageUtil.readPluginPackageProperties(
1199                    displayName, properties);
1200            }
1201            else {
1202                String xml = StringUtil.read(is);
1203
1204                xml = XMLFormatter.fixProlog(xml);
1205
1206                return PluginPackageUtil.readPluginPackageXml(xml);
1207            }
1208        }
1209        catch (Exception e) {
1210            _log.error(file.getPath() + ": " + e.toString());
1211        }
1212        finally {
1213            if (is != null) {
1214                try {
1215                    is.close();
1216                }
1217                catch (IOException ioe) {
1218                }
1219            }
1220
1221            if (zipFile != null) {
1222                try {
1223                    zipFile.close();
1224                }
1225                catch (IOException ioe) {
1226                }
1227            }
1228        }
1229
1230        return null;
1231    }
1232
1233    protected void rewriteFiles(File srcDir) throws Exception {
1234        String[] files = FileUtil.listFiles(srcDir + "/WEB-INF/");
1235
1236        for (int i = 0; i < files.length; i++) {
1237            String fileName = GetterUtil.getString(
1238                FileUtil.getShortFileName(files[i]));
1239
1240            // LEP-6415
1241
1242            if (fileName.equalsIgnoreCase("mule-config.xml")) {
1243                continue;
1244            }
1245
1246            String ext = GetterUtil.getString(FileUtil.getExtension(files[i]));
1247
1248            if (!ext.equalsIgnoreCase("xml")) {
1249                continue;
1250            }
1251
1252            // Make sure to rewrite any XML files to include external entities
1253            // into same file. See LEP-3142.
1254
1255            File file = new File(srcDir + "/WEB-INF/" + files[i]);
1256
1257            try {
1258                Document doc = SAXReaderUtil.read(file);
1259
1260                String content = doc.formattedString(StringPool.TAB, true);
1261
1262                FileUtil.write(file, content);
1263            }
1264            catch (Exception e) {
1265                if (_log.isWarnEnabled()) {
1266                    _log.warn(
1267                        "Unable to format " + file + ": " + e.getMessage());
1268                }
1269            }
1270        }
1271    }
1272
1273    protected void updateDeployDirectory(File srcFile) throws Exception {
1274    }
1275
1276    protected void updateGeronimoWebXml(
1277            File srcFile, String displayName, PluginPackage pluginPackage)
1278        throws Exception {
1279
1280        if (!appServerType.startsWith(ServerDetector.GERONIMO_ID)) {
1281            return;
1282        }
1283
1284        File geronimoWebXml = new File(srcFile + "/WEB-INF/geronimo-web.xml");
1285
1286        Document doc = SAXReaderUtil.read(geronimoWebXml);
1287
1288        Element root = doc.getRootElement();
1289
1290        Element environmentEl = root.element("environment");
1291
1292        Element moduleIdEl = environmentEl.element("moduleId");
1293
1294        Element artifactIdEl = moduleIdEl.element("artifactId");
1295
1296        String artifactIdText = GetterUtil.getString(artifactIdEl.getText());
1297
1298        if (!artifactIdText.equals(displayName)) {
1299            artifactIdEl.setText(displayName);
1300
1301            String content = doc.formattedString();
1302
1303            FileUtil.write(geronimoWebXml, content);
1304
1305            if (_log.isInfoEnabled()) {
1306                _log.info("Modifying Geronimo " + geronimoWebXml);
1307            }
1308        }
1309    }
1310
1311    protected void updateWebXml(
1312            File webXml, File srcFile, String displayName,
1313            PluginPackage pluginPackage)
1314        throws Exception {
1315
1316        String content = FileUtil.read(webXml);
1317
1318        int x = content.indexOf("<display-name>");
1319
1320        if (x != -1) {
1321            int y = content.indexOf("</display-name>", x);
1322
1323            y = content.indexOf(">", y) + 1;
1324
1325            content = content.substring(0, x) + content.substring(y);
1326        }
1327
1328        double webXmlVersion = 2.3;
1329
1330        Document webXmlDoc = SAXReaderUtil.read(content);
1331
1332        Element webXmlRoot = webXmlDoc.getRootElement();
1333
1334        webXmlVersion = GetterUtil.getDouble(
1335            webXmlRoot.attributeValue("version"), webXmlVersion);
1336
1337        // Merge extra content
1338
1339        String extraContent = getExtraContent(
1340            webXmlVersion, srcFile, displayName);
1341
1342        if (webXmlVersion > 2.3) {
1343            while (true) {
1344                int pos = extraContent.indexOf(
1345                    "<param-name>servlet-2.4-dispatcher</param-name>");
1346
1347                if (pos == -1) {
1348                    break;
1349                }
1350
1351                x = extraContent.lastIndexOf("<init-param>", pos);
1352                int y = extraContent.indexOf("</init-param>", pos);
1353
1354                extraContent =
1355                    extraContent.substring(0, x) +
1356                        extraContent.substring(y + 13);
1357            }
1358        }
1359
1360        int pos = content.indexOf("</web-app>");
1361
1362        String newContent =
1363            content.substring(0, pos) + extraContent +
1364            content.substring(pos, content.length());
1365
1366        // Replace old package names
1367
1368        newContent = StringUtil.replace(
1369            newContent, "com.liferay.portal.shared.",
1370            "com.liferay.portal.kernel.");
1371
1372        newContent = WebXMLBuilder.organizeWebXML(newContent);
1373
1374        FileUtil.write(webXml, newContent, true);
1375
1376        if (_log.isInfoEnabled()) {
1377            _log.info("Modifying Servlet " + webXmlVersion + " " + webXml);
1378        }
1379    }
1380
1381    protected String baseDir;
1382    protected String destDir;
1383    protected String appServerType;
1384    protected String portletTaglibDTD;
1385    protected String portletExtTaglibDTD;
1386    protected String securityTaglibDTD;
1387    protected String themeTaglibDTD;
1388    protected String uiTaglibDTD;
1389    protected String utilTaglibDTD;
1390    protected boolean unpackWar;
1391    protected String filePattern;
1392    protected String jbossPrefix;
1393    protected String tomcatLibDir;
1394    protected List<String> wars;
1395    protected List<String> jars;
1396
1397    private static final String _PORTAL_CLASS_LOADER =
1398        "com.liferay.support.tomcat.loader.PortalClassLoader";
1399
1400    private static Log _log = LogFactoryUtil.getLog(BaseDeployer.class);
1401
1402}