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