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