org.getobjects.appserver.products.WOPackageLinker.java Source code

Java tutorial

Introduction

Here is the source code for org.getobjects.appserver.products.WOPackageLinker.java

Source

/*
  Copyright (C) 2006-2014 Helge Hess
    
  This file is part of Go.
    
  Go is free software; you can redistribute it and/or modify it under
  the terms of the GNU Lesser General Public License as published by the
  Free Software Foundation; either version 2, or (at your option) any
  later version.
    
  Go is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  License for more details.
    
  You should have received a copy of the GNU Lesser General Public
  License along with Go; see the file COPYING.  If not, write to the
  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  02111-1307, USA.
*/

package org.getobjects.appserver.products;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.getobjects.appserver.core.WOApplication;
import org.getobjects.appserver.core.WOClassResourceManager;
import org.getobjects.appserver.core.WOCompoundResourceManager;
import org.getobjects.appserver.core.WOProjectDirectoryResourceManager;
import org.getobjects.appserver.core.WOResourceManager;
import org.getobjects.foundation.UObject;
import org.getobjects.foundation.UString;

/**
 * WOPackageLinker
 * <p>
 * This class is used by WOApplication to load required packages for the
 * application.
 * <p>
 * THREAD: this class is not threadsafe.
 */
// TODO: would be nice to rewrite this somehow based on GoProducts.
public class WOPackageLinker {
    private static String goLinkFile = "golink.txt";
    private static String jopeLinkFile = "jopelink.txt";

    protected final Log log = LogFactory.getLog("WOPackageLinker");

    /* used to protect against recursive loads */
    protected Set<String> packagesInLoad;

    protected GoProductManager goProductManager;
    protected List<WOResourceManager> resourceManagers;

    protected boolean enableCaching;

    public WOPackageLinker(boolean _enableCaching, GoProductManager _pd) {
        this.enableCaching = _enableCaching;
        this.goProductManager = _pd;
        this.resourceManagers = new ArrayList<WOResourceManager>(8);
        this.packagesInLoad = new HashSet<String>(16);
    }

    /* main entry for applications */

    /**
     * This is called by WOApplication.init() to setup its WOResourceManager. It
     * invokes the WOPackageLinker which results in some WOResourceManager.
     */
    public static WOResourceManager linkApplication(WOApplication _app) {
        final WOPackageLinker linker = new WOPackageLinker(_app.isCachingEnabled(), _app.goProductManager());

        final String projectDir = _app.projectDirectory();
        if (UObject.isEmpty(projectDir))
            /* first link the Java package the application lives in */
            linker.linkClass(_app.getClass());
        else
            linker.linkProjectDirectory(projectDir, _app.getClass());

        /* then process the jopelink.txt of the application */
        URL linkSpec = _app.getClass().getResource(goLinkFile);
        if (linkSpec == null)
            linkSpec = _app.getClass().getResource(jopeLinkFile);
        linker.linkWithSpecification(linkSpec);

        /* link system frameworks */
        // TBD: why after the initial link spec?
        _app.linkDefaultPackages(linker);

        /* finally register application package as a product */

        final GoProductManager pm = _app.goProductManager();
        if (pm != null)
            pm.loadProduct("MAIN", _app.getClass().getPackage().getName());

        /* retrieve the resulting resource manager */
        return linker.resourceManager();
    }

    /* accessors */

    public WOResourceManager resourceManager() {
        if (this.resourceManagers == null)
            return null;
        if (this.resourceManagers.size() == 0)
            return null;
        if (this.resourceManagers.size() == 1)
            return this.resourceManagers.get(0);

        return new WOCompoundResourceManager(this.resourceManagers, this.enableCaching);
    }

    /* main entry points */

    public boolean linkWithSpecification(final URL _url) {
        if (_url == null)
            return false;

        if (this.log.isDebugEnabled())
            this.log.debug("link specification: " + _url);

        InputStream in = null;
        try {
            if ((in = _url.openStream()) == null)
                return false;

        } catch (IOException e) {
            this.log.error("could not open link specification: " + _url, e);
            return false;
        }

        final String[] lines = UString.loadLinesFromFile(in, true /* trim */, "\\" /* unfold */,
                lineCommentStarters);
        if (lines == null)
            return false;

        for (final String line : lines)
            this.linkFramework(line);

        return true;
    }

    private static final String[] lineCommentStarters = { "#", "//" };

    /* linking packages */

    public void addResourceManager(WOResourceManager _rm) {
        if (_rm == null)
            return;

        // scan whether the manager is already in the queue

        if (!this.resourceManagers.contains(_rm))
            this.resourceManagers.add(_rm);
    }

    public boolean linkFramework(String _pkg) {
        if (_pkg == null)
            return false;
        if (_pkg.length() == 0)
            return false;

        /* avoid load cycles */
        if (this.packagesInLoad.contains(_pkg))
            return true;
        this.packagesInLoad.add(_pkg);

        this.log.debug("  link framework: " + _pkg);

        // TBD: use active loader?
        final ClassLoader loader = this.getClass().getClassLoader();

        /* load all classes of the framework to let us cache the dynamic elements */

        /* first lookup base class for package (used as the hook) */
        // Note: the new 'package-info.java' doesn't contain a class

        Class pkgbase = null;
        try {
            pkgbase = Class.forName(_pkg + "." + "WOFramework", true, loader);
        } catch (ClassNotFoundException e) {
            this.log.debug("    did not find package base class", null /* e2 */);
        }

        if (pkgbase == null) {
            this.log.warn("    could not link package: " + _pkg);
            return false;
        }
        this.log.debug("    using base class:" + pkgbase);

        /* link */

        final WOPackageLinker linker = new WOPackageLinker(this.enableCaching, this.goProductManager);
        linker.linkClass(pkgbase);

        /* next check whether the package wants to link something */

        // TODO: check whether this works properly
        URL deplink = pkgbase.getResource(goLinkFile);
        if (deplink == null)
            deplink = pkgbase.getResource(jopeLinkFile);
        if (deplink != null) {
            this.log.debug("    linking framework dependencies ...");
            linker.linkWithSpecification(deplink);
        }

        /* link system frameworks */
        // TODO: we get an runaway when calling this, find out why
        // String sysbase = WOApplication.class.getPackage().getName();
        // linker.linkFramework(sysbase + ".elements");
        // linker.linkFramework(sysbase);

        /* retrieve the resulting resource manager */
        final WOResourceManager rm = linker.resourceManager();
        if (rm instanceof WOCompoundResourceManager) {
            final WOCompoundResourceManager crm = (WOCompoundResourceManager) rm;
            for (WOResourceManager erm : crm.resourceManagers())
                this.addResourceManager(erm);
        } else
            this.addResourceManager(rm);

        /* register the product as a GoClass */

        if (this.goProductManager != null) {
            if (!this.goProductManager.loadProduct(null, _pkg)) {
                this.log.warn("could not register linked framework as a product: " + _pkg);
            }
        }

        return true;
    }

    public boolean linkClass(final Class _cls) {
        final WOResourceManager rm = new WOClassResourceManager(_cls, this.enableCaching);
        if (rm == null)
            return false;

        this.addResourceManager(rm);
        return true;
    }

    public boolean linkProjectDirectory(final String _projectDir, Class _cls) {
        final WOResourceManager rm = new WOProjectDirectoryResourceManager(_projectDir, _cls, this.enableCaching);
        if (rm == null)
            return false;

        this.log.info("linking WOProjectDirectory: " + _projectDir);
        this.addResourceManager(rm);
        return true;
    }
}