org.trianacode.taskgraph.tool.FileToolbox.java Source code

Java tutorial

Introduction

Here is the source code for org.trianacode.taskgraph.tool.FileToolbox.java

Source

/*
 * Copyright 2004 - 2009 University of Cardiff.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.trianacode.taskgraph.tool;

import org.apache.commons.logging.Log;
import org.thinginitself.http.util.MimeHandler;
import org.thinginitself.streamable.Streamable;
import org.thinginitself.streamable.StreamableFile;
import org.thinginitself.streamable.StreamableStream;
import org.trianacode.config.TrianaProperties;
import org.trianacode.enactment.logging.Loggers;
import org.trianacode.taskgraph.TaskException;
import org.trianacode.taskgraph.Unit;
import org.trianacode.taskgraph.imp.ToolImp;
import org.trianacode.taskgraph.proxy.java.JavaProxy;
import org.trianacode.taskgraph.ser.XMLReader;
import org.trianacode.taskgraph.tool.creators.type.ClassHierarchy;
import org.trianacode.taskgraph.util.FileUtils;
import org.trianacode.taskgraph.util.ToolUtils;
import org.trianacode.taskgraph.util.UrlUtils;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * Class Description Here...
 *
 * @author Andrew Harrison
 * @version $Revision:$
 */

public class FileToolbox implements Toolbox {

    private static Log log = Loggers.TOOL_LOGGER;

    /**
     * constants for directory names where native and java libs are stored in a toolbox. For a toolbox to know where
     * these things are and have them loaded, and exposed, these naming convention must be followed.
     * <p/>
     * The OS-specific dir names should all be within a 'nativ' dir.
     */
    public static final String NATIVE_DIR = "nativ";
    public static final String WIN_32_DIR = "win32";
    public static final String WIN_64_DIR = "win64";
    public static final String OSX_DIR = "osx";
    public static final String OSX_32_DIR = "osx32";
    public static final String OSX_64_DIR = "osx64";
    public static final String NUX_32_DIR = "nux32";
    public static final String NUX_64_DIR = "nux64";
    public static final String LIB_DIR = "lib";
    public static final String HELP_DIR = "help";

    public static final String EXT_TASKGRAPH = ".xml";
    public static final String EXT_JAVA_CLASS = ".class";

    public static String[] excludedDirectories = { "CVS", "src", "lib" };
    public static String[] extensions = { ".xml", ".class", ".jar" };

    public static String[] nativeDirs = { WIN_32_DIR, WIN_64_DIR, OSX_DIR, OSX_32_DIR, OSX_64_DIR, NUX_32_DIR,
            NUX_64_DIR };

    private String path;
    private String type;
    private String name;
    private Map<String, Tool> tools = new HashMap<String, Tool>();

    private ToolClassLoader loader = new ToolClassLoader();

    private TrianaProperties properties;

    private Map<URL, Object> resolved = new ConcurrentHashMap<URL, Object>();

    public FileToolbox(String path, String name, TrianaProperties properties) {
        this.path = path;
        this.properties = properties;
        this.type = FileToolboxLoader.LOCAL_TYPE;
        this.name = name;

        //        System.out.println("Tool : " + name + " Path : " + path);
    }

    public FileToolbox(String path, TrianaProperties properties) {
        this(path, UrlUtils.getLastFilePathComponent(path), properties);
    }

    public FileToolbox(File file) {
        file.mkdirs();
        this.path = file.getAbsolutePath();
        this.type = FileToolboxLoader.LOCAL_TYPE;
        this.name = file.getName();
    }

    public TrianaProperties getProperties() {
        return properties;
    }

    @Override
    public void setProperties(TrianaProperties properties) {
        this.properties = properties;
    }

    public ClassLoader getClassLoader() {
        return loader;
    }

    /**
     * get relative paths pointing to library files (.class, .jar)
     *
     * @return
     */
    public List<String> getLibPaths() {
        return loader.getLibPaths();
    }

    /**
     * get a list of local files that can browsed by a user. Any file not equal to or a child of one of these strings
     * will have access denied.
     *
     * @return
     */
    public List<String> getVisibleRoots() {
        return loader.getVisibleRools();
    }

    /**
     * attempt to get a local file with a path that is a child of the root of the toolbox
     *
     * @param relativePath
     * @return
     */
    public File getFile(String relativePath) {
        return loader.getFile(relativePath);
    }

    public String getClassPath() {
        return loader.getClassPath();
    }

    public void loadTools() throws Exception {
        ClassLoaders.addClassLoader(loader);
        URL url = UrlUtils.toURL(getPath());
        loader.addToolBox(url);
        TypesMap.load(url);
        this.tools = resolveTools();
    }

    @Override
    public void refresh(URL url) throws Exception {
        List<Tool> ts = resolveTools(url);
        for (Tool t : ts) {
            this.tools.put(t.getQualifiedToolName(), t);
        }
    }

    @Override
    public List<Tool> getTools(URL url) {
        List<Tool> t = new ArrayList<Tool>();
        List<Tool> tools = getTools();
        for (Tool tool : tools) {
            if (tool.getDefinitionPath().equals(url)) {
                t.add(tool);
            }
        }
        return t;
    }

    @Override
    public List<Tool> getTools() {
        return new ArrayList(tools.values());
    }

    @Override
    public void addTool(Tool tool) {
        tool.setToolBox(this);
        tools.put(tool.getQualifiedToolName(), tool);
    }

    @Override
    public Tool getTool(String name) {
        return tools.get(name);
    }

    @Override
    public Tool removeTool(String name) {
        return tools.remove(name);
    }

    @Override
    public Tool deleteTool(String name) {
        Tool tool = removeTool(name);
        if (tool != null) {
            deleteLocalTool(tool);
            return tool;
        }
        return null;

    }

    public String getPath() {
        return path;
    }

    public String getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    private boolean deleteLocalTool(Tool tool) {
        File f = UrlUtils.getExistingFile(tool.getDefinitionPath());
        if (f != null && !f.getName().endsWith(".jar")) {
            f.delete();
            return true;
        }
        return false;
    }

    /**
     *
     */
    protected Map<String, Tool> resolveTools() {
        List<URL> urls = new ArrayList<URL>();
        URL toolboxUrl = UrlUtils.toURL(getPath());
        urls.addAll(findLocal(toolboxUrl));
        Map<String, Tool> ret = new HashMap<String, Tool>();
        for (URL url : urls) {
            try {
                List<Tool> tools = resolveTools(url);
                //                System.out.println("Tool url : " + url);
                for (Tool tool : tools) {
                    //                    System.out.println("Tool path : " + tool.getDefinitionPath().getPath());
                    ret.put(tool.getQualifiedToolName(), tool);
                }
            } catch (Exception e) {
                System.out.println("Error in " + url.toString());
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * resolve tools from a particular URL. A single URL can contain more than one tool for example if it's a jar.
     *
     * @param url
     * @return
     * @throws Exception
     */
    protected List<Tool> resolveTools(URL url) throws Exception {
        Streamable streamable = getToolStream(url);
        if (streamable == null || !streamable.hasInputStream()) {
            return null;
        }
        String mime = streamable.getMimeType();
        List<Tool> tools = new ArrayList<Tool>();
        if (url.getPath().endsWith(EXT_TASKGRAPH)) {
            tools = processXml(streamable);
        } else if (url.getPath().endsWith(".jar")) {
            tools = processJar(url, streamable);
        } else if (url.getPath().endsWith(EXT_JAVA_CLASS)) {
            tools = processClass(url);
        }
        if (tools != null) {
            for (Tool tool : tools) {
                tool.setDefinitionPath(url);
                tool.setToolBox(this);
            }
        }
        return tools;
    }

    /**
     * get a streamable from a tool URL
     *
     * @param url
     * @return
     * @throws Exception
     */
    protected Streamable getToolStream(URL url) throws Exception {
        if (UrlUtils.isFile(url)) {
            File f = new File(url.toURI());
            if (!f.exists()) {
                return null;
            }
            return new StreamableFile(f, MimeHandler.getMime(f.getName()));
        }
        return null;
    }

    /**
     * find tools on the local file system
     *
     * @param url
     * @return
     */
    private List<URL> findLocal(URL url) {
        ArrayList<URL> files = new ArrayList<URL>();
        File f = UrlUtils.getExistingFile(url);
        if (f == null) {
            return files;
        }
        if (f.getName().startsWith(".")) {
            return files;
        }
        for (String extDir : excludedDirectories) {
            if (f.getName().equals(extDir)) {
                return files;
            }
        }
        if (f.isDirectory()) {
            File[] fs = f.listFiles(new FilenameFilter() {
                public boolean accept(File file, String s) {
                    File child = new File(file, s);
                    if (child.isDirectory()) {
                        return true;
                    } else {
                        for (String ext : extensions) {
                            if (child.getName().endsWith(ext)) {
                                return true;
                            }
                        }
                    }
                    return false;
                }
            });
            for (File file : fs) {
                URL furl = UrlUtils.fromFile(file);
                if (furl != null && resolved.get(furl) == null) {
                    files.addAll(findLocal(furl));
                    resolved.put(furl, new Object());
                }
            }
        } else {
            URL furl = UrlUtils.fromFile(f);
            if (furl != null && resolved.get(furl) == null) {
                files.add(furl);
                resolved.put(furl, new Object());
            }
        }
        return files;
    }

    /**
     * process an XML tool description
     *
     * @param streamable
     * @return
     * @throws Exception
     */
    private List<Tool> processXml(Streamable streamable) throws Exception {
        XMLReader reader = null;
        try {
            reader = new XMLReader(new BufferedReader(new InputStreamReader(streamable.getInputStream())));
            Tool tool = reader.readComponent(getProperties());
            if (tool != null) {
                return Arrays.asList(tool);
            }
            return new ArrayList<Tool>();
        } catch (Exception e) {
            e.printStackTrace();
            log.debug("error reading xml file ", e);
            throw new ToolException("Error reading tool :" + FileUtils.formatThrowable(e));
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                    reader = null;
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
    }

    /**
     * process a jar file
     *
     * @param url
     * @param streamable
     * @return
     * @throws Exception
     */
    private List<Tool> processJar(URL url, Streamable streamable) throws Exception {
        List<Tool> ret = new ArrayList<Tool>();
        InputStream in = streamable.getInputStream();
        if (!(in instanceof ZipInputStream)) {
            in = new ZipInputStream(in);
        }
        ZipInputStream zin = (ZipInputStream) in;
        ZipEntry entry;
        while ((entry = zin.getNextEntry()) != null) {
            if (entry.getName().endsWith(EXT_TASKGRAPH)) {
                byte[] buff = new byte[2048];
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                int c;
                while ((c = zin.read(buff)) != -1) {
                    bout.write(buff, 0, c);
                }
                ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
                List<Tool> xmls = processXml(new StreamableStream(bin));
                ret.addAll(xmls);
            } else if (entry.getName().endsWith(EXT_JAVA_CLASS)) {
                List<Tool> clss = processClass(new URL("jar:" + url.toString() + "!/" + entry.getName()));
                ret.addAll(clss);
            }
        }
        return ret;
    }

    /**
     * process a java class file
     *
     * @param url
     * @return
     * @throws Exception
     */
    private List<Tool> processClass(URL url) throws Exception {
        try {
            ClassHierarchy ch = TypesMap.isType(url.toString(), Unit.class.getName());
            log.debug("ToolResolver.add class hierarchy:" + ch);
            if (ch == null) {
                ch = TypesMap.getAnnotated(url.toString());
            }
            log.debug("ToolResolver.add class hierarchy after trying annotations:" + ch + " for url " + url);

            if (ch != null) {
                Tool tool = createTool(ch.getName());
                if (tool != null) {

                    return Arrays.asList(tool);
                }
            }
        } catch (Error error) {
            System.out.println(url.toString() + " " + error.getLocalizedMessage());
        }
        return new ArrayList<Tool>();
    }

    /**
     * instantiate a tool
     *
     * @param className
     * @return
     */
    protected Tool createTool(String className) throws Exception {
        try {
            ToolImp tool = new ToolImp(getProperties());
            tool.setDefinitionType(Tool.DEFINITION_JAVA_CLASS);
            tool.setToolName(ToolUtils.getClassName(className));
            tool.setToolPackage(ToolUtils.getPackageName(className));
            tool.setProxy(new JavaProxy(tool.getToolName(), tool.getToolPackage()));

            return tool;
        } catch (TaskException e) {
            log.warn("Error creating tool:", e);
            return null;
        }
    }

}