001    /**
002     * Copyright (c) 2000-2012 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.SortedArrayList;
019    import com.liferay.portal.kernel.util.StringBundler;
020    import com.liferay.portal.kernel.util.StringPool;
021    import com.liferay.portal.kernel.util.StringUtil;
022    import com.liferay.portal.kernel.util.UniqueList;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.util.FileImpl;
025    import com.liferay.portal.util.PropsValues;
026    
027    import java.io.File;
028    import java.io.FileInputStream;
029    import java.io.FilenameFilter;
030    
031    import java.util.ArrayList;
032    import java.util.Collections;
033    import java.util.HashMap;
034    import java.util.List;
035    import java.util.Map;
036    import java.util.Properties;
037    
038    import org.apache.oro.io.GlobFilenameFilter;
039    import org.apache.tools.ant.DirectoryScanner;
040    
041    /**
042     * @author Alexander Chow
043     * @author Brian Wing Shun Chan
044     */
045    public class PluginsEnvironmentBuilder {
046    
047            public static void main(String[] args) throws Exception {
048                    try {
049                            File dir = new File(System.getProperty("plugins.env.dir"));
050    
051                            new PluginsEnvironmentBuilder(dir);
052                    }
053                    catch (Exception e) {
054                            e.printStackTrace();
055                    }
056            }
057    
058            public PluginsEnvironmentBuilder(File dir) throws Exception {
059                    DirectoryScanner ds = new DirectoryScanner();
060    
061                    ds.setBasedir(dir);
062                    ds.setIncludes(new String[] {"**\\liferay-plugin-package.properties"});
063    
064                    ds.scan();
065    
066                    String dirName = dir.getCanonicalPath();
067    
068                    String[] fileNames = ds.getIncludedFiles();
069    
070                    for (String fileName : fileNames) {
071                            setupProject(dirName, fileName);
072                    }
073            }
074    
075            protected void addClasspathEntry(StringBundler sb, String jar) {
076                    addClasspathEntry(sb, jar, null);
077            }
078    
079            protected void addClasspathEntry(
080                    StringBundler sb, String jar, Map<String, String> attributes) {
081    
082                    sb.append("\t<classpathentry kind=\"lib\" path=\"");
083                    sb.append(jar);
084    
085                    if ((attributes == null) || attributes.isEmpty()) {
086                            sb.append("\" />\n");
087    
088                            return;
089                    }
090    
091                    sb.append("\">\n\t\t<attributes>\n");
092    
093                    for (Map.Entry<String, String> entry : attributes.entrySet()) {
094                            sb.append("\t\t\t<attribute name=\"");
095                            sb.append(entry.getKey());
096                            sb.append("\" value=\"");
097                            sb.append(entry.getValue());
098                            sb.append("\" />\n");
099                    }
100    
101                    sb.append("\t\t</attributes>\n\t</classpathentry>\n");
102            }
103    
104            protected List<String> getCommonJars() {
105                    List<String> jars = new ArrayList<String>();
106    
107                    jars.add("commons-logging.jar");
108                    jars.add("log4j.jar");
109                    jars.add("util-bridges.jar");
110                    jars.add("util-java.jar");
111                    jars.add("util-taglib.jar");
112    
113                    return jars;
114            }
115    
116            protected List<String> getImportSharedJars(File projectDir)
117                    throws Exception {
118    
119                    File buildXmlFile = new File(projectDir, "build.xml");
120    
121                    String content = _fileUtil.read(buildXmlFile);
122    
123                    int x = content.indexOf("import.shared");
124    
125                    if (x == -1) {
126                            return Collections.emptyList();
127                    }
128    
129                    x = content.indexOf("value=\"", x);
130                    x = content.indexOf("\"", x);
131    
132                    int y = content.indexOf("\" />", x);
133    
134                    if ((x == -1) || (y == -1)) {
135                            return Collections.emptyList();
136                    }
137    
138                    String[] importShared = StringUtil.split(content.substring(x + 1, y));
139    
140                    if (importShared.length == 0) {
141                            return Collections.emptyList();
142                    }
143    
144                    List<String> jars = new ArrayList<String>();
145    
146                    for (String currentImportShared : importShared) {
147                            jars.add(currentImportShared + ".jar");
148                    }
149    
150                    return jars;
151            }
152    
153            protected List<String> getPortalDependencyJars(Properties properties) {
154                    String[] dependencyJars = StringUtil.split(
155                            properties.getProperty(
156                                    "portal-dependency-jars",
157                                    properties.getProperty("portal.dependency.jars")));
158    
159                    return ListUtil.toList(dependencyJars);
160            }
161    
162            protected List<String> getRequiredDeploymentContextsJars(
163                            File libDir, Properties properties)
164                    throws Exception {
165    
166                    List<String> jars = new ArrayList<String>();
167    
168                    String[] requiredDeploymentContexts = StringUtil.split(
169                            properties.getProperty("required-deployment-contexts"));
170    
171                    for (String requiredDeploymentContext : requiredDeploymentContexts) {
172                            if (_fileUtil.exists(
173                                            libDir.getCanonicalPath() + "/" +
174                                                    requiredDeploymentContext + "-service.jar")) {
175    
176                                    jars.add(requiredDeploymentContext + "-service.jar");
177                            }
178                    }
179    
180                    return jars;
181            }
182    
183            protected void setupProject(String dirName, String fileName)
184                    throws Exception {
185    
186                    File propertiesFile = new File(dirName + "/" + fileName);
187    
188                    Properties properties = new Properties();
189    
190                    properties.load(new FileInputStream(propertiesFile));
191    
192                    List<String> jars = new SortedArrayList<String>();
193    
194                    jars.addAll(getCommonJars());
195    
196                    List<String> dependencyJars = getPortalDependencyJars(properties);
197    
198                    jars.addAll(dependencyJars);
199    
200                    File projectDir = new File(propertiesFile.getParent() + "/../..");
201    
202                    jars.addAll(getImportSharedJars(projectDir));
203    
204                    File libDir = new File(propertiesFile.getParent() + "/lib");
205    
206                    jars.addAll(getRequiredDeploymentContextsJars(libDir, properties));
207    
208                    writeEclipseFiles(libDir, projectDir, dependencyJars);
209    
210                    String libDirPath = StringUtil.replace(
211                            libDir.getPath(), StringPool.BACK_SLASH, StringPool.SLASH);
212    
213                    List<String> ignores = ListUtil.fromFile(
214                            libDir.getCanonicalPath() + "/../.gitignore");
215    
216                    if (!libDirPath.contains("/ext/") && !ignores.contains("/lib")) {
217                            File gitignoreFile = new File(
218                                    libDir.getCanonicalPath() + "/.gitignore");
219    
220                            System.out.println("Updating " + gitignoreFile);
221    
222                            String[] gitIgnores = jars.toArray(new String[jars.size()]);
223    
224                            for (int i = 0; i < gitIgnores.length; i++) {
225                                    String gitIgnore = gitIgnores[i];
226    
227                                    if (Validator.isNotNull(gitIgnore) &&
228                                            !gitIgnore.startsWith("/")) {
229    
230                                            gitIgnores[i] = "/" + gitIgnore;
231                                    }
232                            }
233    
234                            _fileUtil.write(gitignoreFile, StringUtil.merge(gitIgnores, "\n"));
235                    }
236            }
237    
238            protected void writeClasspathFile(
239                            File libDir, List<String> dependencyJars, String projectDirName,
240                            String projectName, boolean javaProject)
241                    throws Exception {
242    
243                    File classpathFile = new File(projectDirName + "/.classpath");
244    
245                    if (!javaProject) {
246                            classpathFile.delete();
247    
248                            return;
249                    }
250    
251                    List<String> globalJars = new UniqueList<String>();
252                    List<String> portalJars = new UniqueList<String>();
253    
254                    List<String> extGlobalJars = new UniqueList<String>();
255                    List<String> extPortalJars = new UniqueList<String>();
256    
257                    String libDirPath = StringUtil.replace(
258                            libDir.getPath(), StringPool.BACK_SLASH, StringPool.SLASH);
259    
260                    if (libDirPath.contains("/ext/")) {
261                            FilenameFilter filenameFilter = new GlobFilenameFilter("*.jar");
262    
263                            for (String dirName : new String[] {"global", "portal"}) {
264                                    File file = new File(libDirPath + "/../ext-lib/" + dirName);
265    
266                                    List<String> jars = ListUtil.toList(file.list(filenameFilter));
267    
268                                    if (dirName.equals("global")) {
269                                            extGlobalJars.addAll(ListUtil.sort(jars));
270    
271                                            File dir = new File(PropsValues.LIFERAY_LIB_GLOBAL_DIR);
272    
273                                            String[] fileNames = dir.list(filenameFilter);
274    
275                                            globalJars.addAll(
276                                                    ListUtil.sort(ListUtil.toList(fileNames)));
277                                            globalJars.removeAll(extGlobalJars);
278                                    }
279                                    else if (dirName.equals("portal")) {
280                                            extPortalJars.addAll(ListUtil.sort(jars));
281    
282                                            File dir = new File(PropsValues.LIFERAY_LIB_PORTAL_DIR);
283    
284                                            String[] fileNames = dir.list(filenameFilter);
285    
286                                            portalJars.addAll(
287                                                    ListUtil.sort(ListUtil.toList(fileNames)));
288                                            portalJars.removeAll(extPortalJars);
289                                    }
290                            }
291                    }
292                    else {
293                            globalJars.add("portlet.jar");
294    
295                            portalJars.addAll(dependencyJars);
296                            portalJars.add("commons-logging.jar");
297                            portalJars.add("log4j.jar");
298    
299                            Collections.sort(portalJars);
300                    }
301    
302                    String[] customJarsArray = libDir.list(new GlobFilenameFilter("*.jar"));
303    
304                    List<String> customJars = null;
305    
306                    if (customJarsArray != null) {
307                            customJars = ListUtil.toList(customJarsArray);
308    
309                            for (String jar : portalJars) {
310                                    customJars.remove(jar);
311                            }
312    
313                            customJars.remove(projectName + "-service.jar");
314                            customJars.remove("util-bridges.jar");
315                            customJars.remove("util-java.jar");
316                            customJars.remove("util-taglib.jar");
317    
318                            Collections.sort(customJars);
319                    }
320                    else {
321                            customJars = new ArrayList<String>();
322                    }
323    
324                    StringBundler sb = new StringBundler();
325    
326                    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
327                    sb.append("<classpath>\n");
328    
329                    for (String sourceDirName : _SOURCE_DIR_NAMES) {
330                            if (_fileUtil.exists(projectDirName + "/" + sourceDirName)) {
331                                    sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
332                                    sb.append("kind=\"src\" path=\"" + sourceDirName + "\" />\n");
333                            }
334                    }
335    
336                    sb.append("\t<classpathentry kind=\"src\" path=\"/portal\" />\n");
337                    sb.append("\t<classpathentry kind=\"con\" ");
338                    sb.append("path=\"org.eclipse.jdt.launching.JRE_CONTAINER\" />\n");
339    
340                    boolean addJunitJars = false;
341    
342                    for (String testType : _TEST_TYPES) {
343                            String testFolder = "test/" + testType;
344    
345                            if (_fileUtil.exists(projectDirName + "/" + testFolder)) {
346                                    addJunitJars = true;
347    
348                                    sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
349                                    sb.append("kind=\"src\" path=\""+ testFolder + "\" />\n");
350                            }
351                    }
352    
353                    if (addJunitJars) {
354                            addClasspathEntry(sb, "/portal/lib/development/junit.jar");
355                            addClasspathEntry(sb, "/portal/lib/portal/commons-io.jar");
356                    }
357    
358                    addClasspathEntry(sb, "/portal/lib/development/activation.jar");
359                    addClasspathEntry(sb, "/portal/lib/development/annotations.jar");
360                    addClasspathEntry(sb, "/portal/lib/development/jsp-api.jar");
361                    addClasspathEntry(sb, "/portal/lib/development/mail.jar");
362                    addClasspathEntry(sb, "/portal/lib/development/servlet-api.jar");
363    
364                    Map<String, String> attributes = new HashMap<String, String>();
365    
366                    if (libDirPath.contains("/ext/")) {
367                            attributes.put("optional", "true");
368                    }
369    
370                    for (String jar : globalJars) {
371                            addClasspathEntry(sb, "/portal/lib/global/" + jar, attributes);
372                    }
373    
374                    for (String jar : portalJars) {
375                            addClasspathEntry(sb, "/portal/lib/portal/" + jar, attributes);
376                    }
377    
378                    addClasspathEntry(sb, "/portal/portal-service/portal-service.jar");
379                    addClasspathEntry(sb, "/portal/util-bridges/util-bridges.jar");
380                    addClasspathEntry(sb, "/portal/util-java/util-java.jar");
381                    addClasspathEntry(sb, "/portal/util-taglib/util-taglib.jar");
382    
383                    for (String jar : extGlobalJars) {
384                            addClasspathEntry(sb, "docroot/WEB-INF/ext-lib/global/" + jar);
385                    }
386    
387                    for (String jar : extPortalJars) {
388                            addClasspathEntry(sb, "docroot/WEB-INF/ext-lib/portal/" + jar);
389                    }
390    
391                    for (String jar : customJars) {
392                            if (libDirPath.contains("/tmp/WEB-INF/lib")) {
393                                    addClasspathEntry(sb, "tmp/WEB-INF/lib/" + jar);
394                            }
395                            else {
396                                    addClasspathEntry(sb, "docroot/WEB-INF/lib/" + jar);
397                            }
398                    }
399    
400                    sb.append("\t<classpathentry kind=\"output\" path=\"bin\" />\n");
401                    sb.append("</classpath>");
402    
403                    System.out.println("Updating " + classpathFile);
404    
405                    String content = StringUtil.replace(
406                            sb.toString(), "\"/portal", "\"/portal-" + _BRANCH);
407    
408                    _fileUtil.write(classpathFile, content);
409            }
410    
411            protected void writeEclipseFiles(
412                            File libDir, File projectDir, List<String> dependencyJars)
413                    throws Exception {
414    
415                    String projectDirName = projectDir.getCanonicalPath();
416    
417                    String projectName = StringUtil.extractLast(
418                            projectDirName, File.separatorChar);
419    
420                    boolean javaProject = false;
421    
422                    for (String sourceDirName : _SOURCE_DIR_NAMES) {
423                            if (_fileUtil.exists(projectDirName + "/" + sourceDirName)) {
424                                    javaProject = true;
425    
426                                    break;
427                            }
428                    }
429    
430                    if (!javaProject) {
431                            System.out.println(
432                                    "Eclipse Java project will not be used because a source " +
433                                            "folder does not exist");
434                    }
435    
436                    writeProjectFile(projectDirName, projectName, javaProject);
437    
438                    writeClasspathFile(
439                            libDir, dependencyJars, projectDirName, projectName, javaProject);
440    
441                    for (String sourceDirName : _SOURCE_DIR_NAMES) {
442                            if (_fileUtil.exists(projectDirName + "/" + sourceDirName)) {
443                                    List<String> gitIgnores = new ArrayList<String>();
444    
445                                    if (sourceDirName.endsWith("ext-impl/src")) {
446                                            gitIgnores.add("/classes");
447                                            gitIgnores.add("/ext-impl.jar");
448                                    }
449                                    else if (sourceDirName.endsWith("ext-service/src")) {
450                                            gitIgnores.add("/classes");
451                                            gitIgnores.add("/ext-service.jar");
452                                    }
453                                    else if (sourceDirName.endsWith("ext-util-bridges/src")) {
454                                            gitIgnores.add("/classes");
455                                            gitIgnores.add("/ext-util-bridges.jar");
456                                    }
457                                    else if (sourceDirName.endsWith("ext-util-java/src")) {
458                                            gitIgnores.add("/classes");
459                                            gitIgnores.add("/ext-util-java.jar");
460                                    }
461                                    else if (sourceDirName.endsWith("ext-util-taglib/src")) {
462                                            gitIgnores.add("/classes");
463                                            gitIgnores.add("/ext-util-taglib.jar");
464                                    }
465                                    else {
466                                            continue;
467                                    }
468    
469                                    String dirName = projectDirName + "/" + sourceDirName + "/../";
470    
471                                    if (gitIgnores.isEmpty()) {
472                                            _fileUtil.delete(dirName + ".gitignore");
473                                    }
474                                    else {
475                                            String gitIgnoresString = StringUtil.merge(
476                                                    gitIgnores, "\n");
477    
478                                            _fileUtil.write(dirName + ".gitignore", gitIgnoresString);
479                                    }
480                            }
481                    }
482    
483                    if (_fileUtil.exists(projectDirName + "/test")) {
484                            _fileUtil.write(
485                                    projectDirName + "/.gitignore", "/test-classes\n/test-results");
486                    }
487                    else {
488                            _fileUtil.delete(projectDirName + "/.gitignore");
489                    }
490            }
491    
492            protected void writeProjectFile(
493                            String projectDirName, String projectName, boolean javaProject)
494                    throws Exception {
495    
496                    StringBundler sb = new StringBundler(17);
497    
498                    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
499                    sb.append("<projectDescription>\n");
500                    sb.append("\t<name>");
501                    sb.append(projectName);
502                    sb.append("-");
503                    sb.append(_BRANCH);
504                    sb.append("</name>\n");
505                    sb.append("\t<comment></comment>\n");
506                    sb.append("\t<projects></projects>\n");
507                    sb.append("\t<buildSpec>\n");
508    
509                    if (javaProject) {
510                            sb.append("\t\t<buildCommand>\n");
511                            sb.append("\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n");
512                            sb.append("\t\t\t<arguments></arguments>\n");
513                            sb.append("\t\t</buildCommand>\n");
514                    }
515    
516                    sb.append("\t</buildSpec>\n");
517                    sb.append("\t<natures>\n");
518    
519                    if (javaProject) {
520                            sb.append("\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n");
521                    }
522    
523                    sb.append("\t</natures>\n");
524                    sb.append("</projectDescription>");
525    
526                    File projectFile = new File(projectDirName + "/.project");
527    
528                    System.out.println("Updating " + projectFile);
529    
530                    _fileUtil.write(projectFile, sb.toString());
531            }
532    
533            private static final String _BRANCH = "trunk";
534    
535            private static final String[] _SOURCE_DIR_NAMES = new String[] {
536                    "docroot/WEB-INF/ext-impl/src", "docroot/WEB-INF/ext-service/src",
537                    "docroot/WEB-INF/ext-util-bridges/src",
538                    "docroot/WEB-INF/ext-util-java/src",
539                    "docroot/WEB-INF/ext-util-taglib/src", "docroot/WEB-INF/service",
540                    "docroot/WEB-INF/src"
541            };
542    
543            private static final String[] _TEST_TYPES = {"integration", "unit"};
544    
545            private static FileImpl _fileUtil = FileImpl.getInstance();
546    
547    }