001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools;
016    
017    import com.liferay.portal.kernel.util.ListUtil;
018    import com.liferay.portal.kernel.util.StringBundler;
019    import com.liferay.portal.kernel.util.StringPool;
020    import com.liferay.portal.kernel.util.StringUtil;
021    import com.liferay.portal.kernel.util.UniqueList;
022    import com.liferay.portal.kernel.util.Validator;
023    import com.liferay.portal.util.FileImpl;
024    import com.liferay.portal.util.PropsValues;
025    
026    import java.io.File;
027    import java.io.FileInputStream;
028    import java.io.FilenameFilter;
029    
030    import java.util.ArrayList;
031    import java.util.Arrays;
032    import java.util.Collections;
033    import java.util.HashMap;
034    import java.util.Iterator;
035    import java.util.List;
036    import java.util.Map;
037    import java.util.Properties;
038    import java.util.Set;
039    import java.util.TreeSet;
040    
041    import org.apache.oro.io.GlobFilenameFilter;
042    import org.apache.tools.ant.DirectoryScanner;
043    
044    /**
045     * @author Alexander Chow
046     * @author Brian Wing Shun Chan
047     */
048    public class PluginsEnvironmentBuilder {
049    
050            public static void main(String[] args) throws Exception {
051                    try {
052                            File dir = new File(System.getProperty("plugins.env.dir"));
053    
054                            new PluginsEnvironmentBuilder(dir);
055                    }
056                    catch (Exception e) {
057                            e.printStackTrace();
058                    }
059            }
060    
061            public PluginsEnvironmentBuilder(File dir) throws Exception {
062                    DirectoryScanner directoryScanner = new DirectoryScanner();
063    
064                    directoryScanner.setBasedir(dir);
065                    directoryScanner.setIncludes(
066                            new String[] {"**\\liferay-plugin-package.properties"});
067    
068                    directoryScanner.scan();
069    
070                    String dirName = dir.getCanonicalPath();
071    
072                    for (String fileName : directoryScanner.getIncludedFiles()) {
073                            setupWarProject(dirName, fileName);
074                    }
075    
076                    directoryScanner = new DirectoryScanner();
077    
078                    directoryScanner.setBasedir(dir);
079                    directoryScanner.setIncludes(new String[] {"**\\build.xml"});
080    
081                    directoryScanner.scan();
082    
083                    for (String fileName : directoryScanner.getIncludedFiles()) {
084                            String content = _fileUtil.read(dirName + "/" + fileName);
085    
086                            boolean osgiProject = content.contains(
087                                    "<import file=\"../../build-common-osgi-plugin.xml\" />");
088                            boolean sharedProject = content.contains(
089                                    "<import file=\"../build-common-shared.xml\" />");
090    
091                            List<String> dependencyJars = Collections.emptyList();
092    
093                            if (osgiProject) {
094                                    int x = content.indexOf("osgi.plugin.portal.lib.jars");
095    
096                                    if (x != -1) {
097                                            x = content.indexOf("value=\"", x);
098                                            x = content.indexOf("\"", x);
099    
100                                            int y = content.indexOf("\"", x + 1);
101    
102                                            dependencyJars = Arrays.asList(
103                                                    StringUtil.split(content.substring(x + 1, y)));
104                                    }
105                            }
106    
107                            if (osgiProject || sharedProject) {
108                                    setupJarProject(
109                                            dirName, fileName, dependencyJars, sharedProject);
110                            }
111                    }
112            }
113    
114            protected void addClasspathEntry(StringBundler sb, String jar) {
115                    addClasspathEntry(sb, jar, null);
116            }
117    
118            protected void addClasspathEntry(
119                    StringBundler sb, String jar, Map<String, String> attributes) {
120    
121                    sb.append("\t<classpathentry kind=\"lib\" path=\"");
122                    sb.append(jar);
123    
124                    if ((attributes == null) || attributes.isEmpty()) {
125                            sb.append("\" />\n");
126    
127                            return;
128                    }
129    
130                    sb.append("\">\n\t\t<attributes>\n");
131    
132                    Iterator<Map.Entry<String, String>> itr =
133                            attributes.entrySet().iterator();
134    
135                    while (itr.hasNext()) {
136                            Map.Entry<String, String> entry = itr.next();
137    
138                            sb.append("\t\t\t<attribute name=\"");
139                            sb.append(entry.getKey());
140                            sb.append("\" value=\"");
141                            sb.append(entry.getValue());
142                            sb.append("\" />\n");
143                    }
144    
145                    sb.append("\t\t</attributes>\n\t</classpathentry>\n");
146            }
147    
148            protected List<String> getCommonJars() {
149                    List<String> jars = new ArrayList<String>();
150    
151                    jars.add("commons-logging.jar");
152                    jars.add("log4j.jar");
153                    jars.add("util-bridges.jar");
154                    jars.add("util-java.jar");
155                    jars.add("util-taglib.jar");
156    
157                    return jars;
158            }
159    
160            protected List<String> getImportSharedJars(File projectDir)
161                    throws Exception {
162    
163                    File buildXmlFile = new File(projectDir, "build.xml");
164    
165                    String content = _fileUtil.read(buildXmlFile);
166    
167                    int x = content.indexOf("import.shared");
168    
169                    if (x == -1) {
170                            return new ArrayList<String>();
171                    }
172    
173                    x = content.indexOf("value=\"", x);
174                    x = content.indexOf("\"", x);
175    
176                    int y = content.indexOf("\" />", x);
177    
178                    if ((x == -1) || (y == -1)) {
179                            return new ArrayList<String>();
180                    }
181    
182                    String[] importShared = StringUtil.split(content.substring(x + 1, y));
183    
184                    if (importShared.length == 0) {
185                            return new ArrayList<String>();
186                    }
187    
188                    List<String> jars = new ArrayList<String>();
189    
190                    for (String currentImportShared : importShared) {
191                            jars.add(currentImportShared + ".jar");
192    
193                            File currentImportSharedLibDir = new File(
194                                    projectDir, "/../../shared/" + currentImportShared + "/lib");
195    
196                            if (!currentImportSharedLibDir.exists()) {
197                                    continue;
198                            }
199    
200                            for (File file : currentImportSharedLibDir.listFiles()) {
201                                    jars.add(file.getName());
202                            }
203                    }
204    
205                    return jars;
206            }
207    
208            protected List<String> getPortalDependencyJars(Properties properties) {
209                    String[] dependencyJars = StringUtil.split(
210                            properties.getProperty(
211                                    "portal-dependency-jars",
212                                    properties.getProperty("portal.dependency.jars")));
213    
214                    return ListUtil.toList(dependencyJars);
215            }
216    
217            protected List<String> getRequiredDeploymentContextsJars(
218                            File libDir, Properties properties)
219                    throws Exception {
220    
221                    List<String> jars = new ArrayList<String>();
222    
223                    String[] requiredDeploymentContexts = StringUtil.split(
224                            properties.getProperty("required-deployment-contexts"));
225    
226                    for (String requiredDeploymentContext : requiredDeploymentContexts) {
227                            if (_fileUtil.exists(
228                                            libDir.getCanonicalPath() + "/" +
229                                                    requiredDeploymentContext + "-service.jar")) {
230    
231                                    jars.add(requiredDeploymentContext + "-service.jar");
232                            }
233                    }
234    
235                    return jars;
236            }
237    
238            protected void setupJarProject(
239                            String dirName, String fileName, List<String> dependencyJars,
240                            boolean sharedProject)
241                    throws Exception {
242    
243                    File buildFile = new File(dirName + "/" + fileName);
244    
245                    File projectDir = new File(buildFile.getParent());
246    
247                    File libDir = new File(projectDir, "lib");
248    
249                    writeEclipseFiles(libDir, projectDir, dependencyJars);
250    
251                    List<String> importSharedJars = getImportSharedJars(projectDir);
252    
253                    if (sharedProject) {
254                            if (!importSharedJars.contains("portal-compat-shared.jar")) {
255                                    importSharedJars.add("portal-compat-shared.jar");
256                            }
257                    }
258    
259                    File gitignoreFile = new File(
260                            projectDir.getCanonicalPath() + "/.gitignore");
261    
262                    String[] gitIgnores = importSharedJars.toArray(
263                            new String[importSharedJars.size()]);
264    
265                    for (int i = 0; i < gitIgnores.length; i++) {
266                            String gitIgnore = gitIgnores[i];
267    
268                            gitIgnore = "/lib/" + gitIgnore;
269    
270                            gitIgnores[i] = gitIgnore;
271                    }
272    
273                    if (gitIgnores.length > 0) {
274                            System.out.println("Updating " + gitignoreFile);
275    
276                            _fileUtil.write(gitignoreFile, StringUtil.merge(gitIgnores, "\n"));
277                    }
278            }
279    
280            protected void setupWarProject(String dirName, String fileName)
281                    throws Exception {
282    
283                    File propertiesFile = new File(dirName + "/" + fileName);
284    
285                    Properties properties = new Properties();
286    
287                    properties.load(new FileInputStream(propertiesFile));
288    
289                    Set<String> jars = new TreeSet<String>();
290    
291                    jars.addAll(getCommonJars());
292    
293                    List<String> dependencyJars = getPortalDependencyJars(properties);
294    
295                    jars.addAll(dependencyJars);
296    
297                    File projectDir = new File(propertiesFile.getParent() + "/../..");
298    
299                    jars.addAll(getImportSharedJars(projectDir));
300    
301                    File libDir = new File(propertiesFile.getParent() + "/lib");
302    
303                    jars.addAll(getRequiredDeploymentContextsJars(libDir, properties));
304    
305                    writeEclipseFiles(libDir, projectDir, dependencyJars);
306    
307                    String libDirPath = StringUtil.replace(
308                            libDir.getPath(), StringPool.BACK_SLASH, StringPool.SLASH);
309    
310                    List<String> ignores = ListUtil.fromFile(
311                            libDir.getCanonicalPath() + "/../.gitignore");
312    
313                    if (libDirPath.contains("/ext/") || ignores.contains("/lib")) {
314                            return;
315                    }
316    
317                    File gitignoreFile = new File(
318                            libDir.getCanonicalPath() + "/.gitignore");
319    
320                    System.out.println("Updating " + gitignoreFile);
321    
322                    String[] gitIgnores = jars.toArray(new String[jars.size()]);
323    
324                    for (int i = 0; i < gitIgnores.length; i++) {
325                            String gitIgnore = gitIgnores[i];
326    
327                            if (Validator.isNotNull(gitIgnore) && !gitIgnore.startsWith("/")) {
328                                    gitIgnores[i] = "/" + gitIgnore;
329                            }
330                    }
331    
332                    _fileUtil.write(gitignoreFile, StringUtil.merge(gitIgnores, "\n"));
333            }
334    
335            protected void writeClasspathFile(
336                            File libDir, List<String> dependencyJars, String projectDirName,
337                            String projectName, boolean javaProject)
338                    throws Exception {
339    
340                    File classpathFile = new File(projectDirName + "/.classpath");
341    
342                    if (!javaProject) {
343                            classpathFile.delete();
344    
345                            return;
346                    }
347    
348                    List<String> globalJars = new UniqueList<String>();
349                    List<String> portalJars = new UniqueList<String>();
350    
351                    List<String> extGlobalJars = new UniqueList<String>();
352                    List<String> extPortalJars = new UniqueList<String>();
353    
354                    String libDirPath = StringUtil.replace(
355                            libDir.getPath(), StringPool.BACK_SLASH, StringPool.SLASH);
356    
357                    if (libDirPath.contains("/ext/")) {
358                            FilenameFilter filenameFilter = new GlobFilenameFilter("*.jar");
359    
360                            for (String dirName : new String[] {"global", "portal"}) {
361                                    File file = new File(libDirPath + "/../ext-lib/" + dirName);
362    
363                                    List<String> jars = ListUtil.toList(file.list(filenameFilter));
364    
365                                    if (dirName.equals("global")) {
366                                            extGlobalJars.addAll(ListUtil.sort(jars));
367    
368                                            File dir = new File(PropsValues.LIFERAY_LIB_GLOBAL_DIR);
369    
370                                            String[] fileNames = dir.list(filenameFilter);
371    
372                                            globalJars.addAll(
373                                                    ListUtil.sort(ListUtil.toList(fileNames)));
374                                            globalJars.removeAll(extGlobalJars);
375                                    }
376                                    else if (dirName.equals("portal")) {
377                                            extPortalJars.addAll(ListUtil.sort(jars));
378    
379                                            File dir = new File(PropsValues.LIFERAY_LIB_PORTAL_DIR);
380    
381                                            String[] fileNames = dir.list(filenameFilter);
382    
383                                            portalJars.addAll(
384                                                    ListUtil.sort(ListUtil.toList(fileNames)));
385                                            portalJars.removeAll(extPortalJars);
386                                    }
387                            }
388                    }
389                    else {
390                            globalJars.add("portlet.jar");
391    
392                            portalJars.addAll(dependencyJars);
393                            portalJars.add("commons-logging.jar");
394                            portalJars.add("log4j.jar");
395    
396                            Collections.sort(portalJars);
397                    }
398    
399                    String[] customJarsArray = libDir.list(new GlobFilenameFilter("*.jar"));
400    
401                    List<String> customJars = null;
402    
403                    if (customJarsArray != null) {
404                            customJars = ListUtil.toList(customJarsArray);
405    
406                            for (String jar : portalJars) {
407                                    customJars.remove(jar);
408                            }
409    
410                            customJars.remove(projectName + "-service.jar");
411                            customJars.remove("util-bridges.jar");
412                            customJars.remove("util-java.jar");
413                            customJars.remove("util-taglib.jar");
414    
415                            Collections.sort(customJars);
416                    }
417                    else {
418                            customJars = new ArrayList<String>();
419                    }
420    
421                    StringBundler sb = new StringBundler();
422    
423                    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
424                    sb.append("<classpath>\n");
425    
426                    for (String sourceDirName : _SOURCE_DIR_NAMES) {
427                            if (_fileUtil.exists(projectDirName + "/" + sourceDirName)) {
428                                    sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
429                                    sb.append("kind=\"src\" path=\"" + sourceDirName + "\" />\n");
430                            }
431                    }
432    
433                    sb.append("\t<classpathentry kind=\"src\" path=\"/portal\" />\n");
434                    sb.append("\t<classpathentry kind=\"con\" ");
435                    sb.append("path=\"org.eclipse.jdt.launching.JRE_CONTAINER\" />\n");
436    
437                    boolean addJunitJars = false;
438    
439                    for (String testType : _TEST_TYPES) {
440                            String testFolder = "test/" + testType;
441    
442                            if (_fileUtil.exists(projectDirName + "/" + testFolder)) {
443                                    addJunitJars = true;
444    
445                                    sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
446                                    sb.append("kind=\"src\" path=\""+ testFolder + "\" />\n");
447                            }
448                    }
449    
450                    if (addJunitJars) {
451                            addClasspathEntry(sb, "/portal/lib/development/junit.jar");
452                            addClasspathEntry(sb, "/portal/lib/development/mockito.jar");
453                            addClasspathEntry(
454                                    sb, "/portal/lib/development/powermock-mockito.jar");
455                            addClasspathEntry(sb, "/portal/lib/development/spring-test.jar");
456                            addClasspathEntry(sb, "/portal/lib/portal/commons-io.jar");
457                    }
458    
459                    addClasspathEntry(sb, "/portal/lib/development/activation.jar");
460                    addClasspathEntry(sb, "/portal/lib/development/annotations.jar");
461                    addClasspathEntry(sb, "/portal/lib/development/jsp-api.jar");
462                    addClasspathEntry(sb, "/portal/lib/development/mail.jar");
463                    addClasspathEntry(sb, "/portal/lib/development/servlet-api.jar");
464    
465                    Map<String, String> attributes = new HashMap<String, String>();
466    
467                    if (libDirPath.contains("/ext/")) {
468                            attributes.put("optional", "true");
469                    }
470    
471                    for (String jar : globalJars) {
472                            addClasspathEntry(sb, "/portal/lib/global/" + jar, attributes);
473                    }
474    
475                    for (String jar : portalJars) {
476                            if (!jar.equals("util-slf4j.jar")) {
477                                    addClasspathEntry(sb, "/portal/lib/portal/" + jar, attributes);
478                            }
479                    }
480    
481                    addClasspathEntry(sb, "/portal/portal-service/portal-service.jar");
482                    addClasspathEntry(sb, "/portal/util-bridges/util-bridges.jar");
483                    addClasspathEntry(sb, "/portal/util-java/util-java.jar");
484    
485                    if (portalJars.contains("util-slf4j.jar")) {
486                            addClasspathEntry(sb, "/portal/util-slf4j/util-slf4j.jar");
487                    }
488    
489                    addClasspathEntry(sb, "/portal/util-taglib/util-taglib.jar");
490    
491                    for (String jar : extGlobalJars) {
492                            addClasspathEntry(sb, "docroot/WEB-INF/ext-lib/global/" + jar);
493                    }
494    
495                    for (String jar : extPortalJars) {
496                            addClasspathEntry(sb, "docroot/WEB-INF/ext-lib/portal/" + jar);
497                    }
498    
499                    for (String jar : customJars) {
500                            if (libDirPath.contains("/tmp/WEB-INF/lib")) {
501                                    addClasspathEntry(sb, "tmp/WEB-INF/lib/" + jar);
502                            }
503                            else if (libDirPath.contains("/docroot/WEB-INF/lib")) {
504                                    addClasspathEntry(sb, "docroot/WEB-INF/lib/" + jar);
505                            }
506                            else {
507                                    addClasspathEntry(sb, "lib/" + jar);
508                            }
509                    }
510    
511                    sb.append("\t<classpathentry kind=\"output\" path=\"bin\" />\n");
512                    sb.append("</classpath>");
513    
514                    System.out.println("Updating " + classpathFile);
515    
516                    String content = StringUtil.replace(
517                            sb.toString(), "\"/portal", "\"/portal-" + _BRANCH);
518    
519                    _fileUtil.write(classpathFile, content);
520            }
521    
522            protected void writeEclipseFiles(
523                            File libDir, File projectDir, List<String> dependencyJars)
524                    throws Exception {
525    
526                    String projectDirName = projectDir.getCanonicalPath();
527    
528                    String projectName = StringUtil.extractLast(
529                            projectDirName, File.separatorChar);
530    
531                    boolean javaProject = false;
532    
533                    for (String sourceDirName : _SOURCE_DIR_NAMES) {
534                            if (_fileUtil.exists(projectDirName + "/" + sourceDirName)) {
535                                    javaProject = true;
536    
537                                    break;
538                            }
539                    }
540    
541                    if (!javaProject) {
542                            System.out.println(
543                                    "Eclipse Java project will not be used because a source " +
544                                            "folder does not exist");
545                    }
546    
547                    writeProjectFile(projectDirName, projectName, javaProject);
548    
549                    writeClasspathFile(
550                            libDir, dependencyJars, projectDirName, projectName, javaProject);
551    
552                    for (String sourceDirName : _SOURCE_DIR_NAMES) {
553                            if (_fileUtil.exists(projectDirName + "/" + sourceDirName)) {
554                                    List<String> gitIgnores = new ArrayList<String>();
555    
556                                    if (sourceDirName.endsWith("ext-impl/src")) {
557                                            gitIgnores.add("/classes");
558                                            gitIgnores.add("/ext-impl.jar");
559                                    }
560                                    else if (sourceDirName.endsWith("ext-service/src")) {
561                                            gitIgnores.add("/classes");
562                                            gitIgnores.add("/ext-service.jar");
563                                    }
564                                    else if (sourceDirName.endsWith("ext-util-bridges/src")) {
565                                            gitIgnores.add("/classes");
566                                            gitIgnores.add("/ext-util-bridges.jar");
567                                    }
568                                    else if (sourceDirName.endsWith("ext-util-java/src")) {
569                                            gitIgnores.add("/classes");
570                                            gitIgnores.add("/ext-util-java.jar");
571                                    }
572                                    else if (sourceDirName.endsWith("ext-util-taglib/src")) {
573                                            gitIgnores.add("/classes");
574                                            gitIgnores.add("/ext-util-taglib.jar");
575                                    }
576                                    else {
577                                            continue;
578                                    }
579    
580                                    String dirName = projectDirName + "/" + sourceDirName + "/../";
581    
582                                    if (gitIgnores.isEmpty()) {
583                                            _fileUtil.delete(dirName + ".gitignore");
584                                    }
585                                    else {
586                                            String gitIgnoresString = StringUtil.merge(
587                                                    gitIgnores, "\n");
588    
589                                            _fileUtil.write(dirName + ".gitignore", gitIgnoresString);
590                                    }
591                            }
592                    }
593    
594                    if (_fileUtil.exists(projectDirName + "/test")) {
595                            _fileUtil.write(
596                                    projectDirName + "/.gitignore", "/test-classes\n/test-results");
597                    }
598                    else {
599                            _fileUtil.delete(projectDirName + "/.gitignore");
600                    }
601            }
602    
603            protected void writeProjectFile(
604                            String projectDirName, String projectName, boolean javaProject)
605                    throws Exception {
606    
607                    StringBundler sb = new StringBundler(17);
608    
609                    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
610                    sb.append("<projectDescription>\n");
611                    sb.append("\t<name>");
612                    sb.append(projectName);
613                    sb.append("-");
614                    sb.append(_BRANCH);
615                    sb.append("</name>\n");
616                    sb.append("\t<comment></comment>\n");
617                    sb.append("\t<projects></projects>\n");
618                    sb.append("\t<buildSpec>\n");
619    
620                    if (javaProject) {
621                            sb.append("\t\t<buildCommand>\n");
622                            sb.append("\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n");
623                            sb.append("\t\t\t<arguments></arguments>\n");
624                            sb.append("\t\t</buildCommand>\n");
625                    }
626    
627                    sb.append("\t</buildSpec>\n");
628                    sb.append("\t<natures>\n");
629    
630                    if (javaProject) {
631                            sb.append("\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n");
632                    }
633    
634                    sb.append("\t</natures>\n");
635                    sb.append("</projectDescription>");
636    
637                    File projectFile = new File(projectDirName + "/.project");
638    
639                    System.out.println("Updating " + projectFile);
640    
641                    _fileUtil.write(projectFile, sb.toString());
642            }
643    
644            private static final String _BRANCH = "6.1.x";
645    
646            private static final String[] _SOURCE_DIR_NAMES = new String[] {
647                    "docroot/WEB-INF/ext-impl/src", "docroot/WEB-INF/ext-service/src",
648                    "docroot/WEB-INF/ext-util-bridges/src",
649                    "docroot/WEB-INF/ext-util-java/src",
650                    "docroot/WEB-INF/ext-util-taglib/src", "docroot/WEB-INF/service",
651                    "docroot/WEB-INF/src", "src"
652            };
653    
654            private static final String[] _TEST_TYPES = {"integration", "unit"};
655    
656            private static FileImpl _fileUtil = FileImpl.getInstance();
657    
658    }