org.pentaho.platform.repository.solution.filebased.FileBasedSolutionRepository.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.platform.repository.solution.filebased.FileBasedSolutionRepository.java

Source

/*
 * This program is free software; you can redistribute it and/or modify it under the 
 * terms of the GNU General Public License, version 2 as published by the Free Software 
 * Foundation.
 *
 * You should have received a copy of the GNU General Public License along with this 
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html 
 * or from the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program 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 General Public License for more details.
 * 
 * Copyright 2005-2008 Pentaho Corporation.  All rights reserved. 
 * 
 * Created on Jun 21, 2005
 */

package org.pentaho.platform.repository.solution.filebased;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.StringTokenizer;

import org.apache.commons.io.IOUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.pentaho.platform.api.engine.IActionSequence;
import org.pentaho.platform.api.engine.IActionSequenceResource;
import org.pentaho.platform.api.engine.IFileInfo;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.api.engine.IPermissionMask;
import org.pentaho.platform.api.engine.IPermissionRecipient;
import org.pentaho.platform.api.engine.IPluginManager;
import org.pentaho.platform.api.engine.IRuntimeContext;
import org.pentaho.platform.api.engine.ISolutionFile;
import org.pentaho.platform.api.engine.ISolutionFilter;
import org.pentaho.platform.api.engine.PentahoAccessControlException;
import org.pentaho.platform.api.repository.ISolutionRepository;
import org.pentaho.platform.api.repository.ISubscriptionRepository;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.services.actionsequence.ActionResource;
import org.pentaho.platform.engine.services.actionsequence.SequenceDefinition;
import org.pentaho.platform.engine.services.solution.SolutionReposHelper;
import org.pentaho.platform.repository.messages.Messages;
import org.pentaho.platform.repository.solution.SolutionRepositoryBase;
import org.pentaho.platform.util.FileHelper;
import org.pentaho.platform.util.StringUtil;
import org.pentaho.platform.util.xml.XmlHelper;
import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper;

/**
 * @author James Dixon TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
 */
public class FileBasedSolutionRepository extends SolutionRepositoryBase {
    /**
     * 
     */
    private static final long serialVersionUID = -8270135463210017284L;

    private ISolutionFilter defaultSolutionFilter = new DefaultSolutionFilter();

    private boolean useActionSequenceCaching = false;

    private boolean repositoryInit = false;

    public FileBasedSolutionRepository() {
        super();
        init();
    }

    @Override
    public void init() {
        if (!repositoryInit) {
            super.init();

            String flag = PentahoSystem.getSystemSetting("filebased-solution-cache", "false"); //$NON-NLS-1$ //$NON-NLS-2$
            try {
                useActionSequenceCaching = Boolean.getBoolean(flag);
            } catch (Exception e) {
                useActionSequenceCaching = false;
            }
            repositoryInit = true;
        }
    }

    public ClassLoader getClassLoader(final String path) {
        File localeDir = new File(PentahoSystem.getApplicationContext().getSolutionPath(path));
        try {
            URLClassLoader loader = new URLClassLoader(new URL[] { localeDir.toURL() }, null);
            return loader;
        } catch (Exception e) {
            error(Messages.getErrorString("SolutionRepository.ERROR_0024_CREATING_CLASSLOADER")); //$NON-NLS-1$
        }
        return null;
    }

    public IActionSequence getActionSequence(final String solutionName, final String actionPath,
            final String sequenceName, final int localLoggingLevel, final int actionOperation) {
        String action;

        IActionSequence actionSequence = null;
        if ((actionPath != null) && !"".equals(actionPath)) { //$NON-NLS-1$
            action = solutionName + File.separator + actionPath + File.separator + sequenceName;
        } else {
            action = solutionName + File.separator + sequenceName;
        }

        if (useActionSequenceCaching) {
            actionSequence = (IActionSequence) getRepositoryObjectFromCache(action);
        }
        if (actionSequence != null) {
            return actionSequence;
        }
        Document actionSequenceDocument = getSolutionDocument(action, actionOperation);
        if (actionSequenceDocument == null) {
            return null;
        }

        actionSequence = SequenceDefinition.ActionSequenceFactory(actionSequenceDocument, sequenceName, actionPath,
                solutionName, this, PentahoSystem.getApplicationContext(), localLoggingLevel);
        if (actionSequence == null) {
            error(Messages.getErrorString("SolutionRepository.ERROR_0016_FAILED_TO_CREATE_ACTION_SEQUENCE", //$NON-NLS-1$
                    action));
            return null;
        }

        if (useActionSequenceCaching) {
            putRepositoryObjectInCache(action, actionSequence);
        }

        return actionSequence;
    }

    public Document getSolutionDocument(final String solutionName, final String actionPath, final String actionName,
            final int actionOperation) {
        return getSolutionDocument(solutionName + File.separator + actionPath + File.separator + actionName,
                actionOperation);
    }

    public Document getSolutionDocument(final String documentPath, final int actionOperation) {
        // TODO: caching
        File file = getFile(documentPath, false);
        // Handle the exception when you have the best knowledge about it.
        if (null == file) {
            // takes care of null pointer exception
            error(Messages.getErrorString("SolutionRepository.ERROR_0001_FILE_DOES_NOT_EXIST", documentPath)); //$NON-NLS-1$
            return null;
        } else {
            if (!file.exists()) {
                error(Messages.getErrorString("SolutionRepository.ERROR_0001_FILE_DOES_NOT_EXIST", documentPath)); //$NON-NLS-1$
                return null;
            } else if (!file.canRead()) {
                error(Messages.getErrorString("SolutionRepository.ERROR_0020_FILE_IS_NOT_READABLE", documentPath)); //$NON-NLS-1$
                return null;
            }
        }

        Document document = null;
        try {
            document = XmlDom4JHelper.getDocFromFile(file, this.getResourceLoader());
        } catch (Exception e) {
            error(Messages.getString("SolutionRepository.ERROR_0009_INVALID_DOCUMENT", documentPath)); //$NON-NLS-1$
            return null;
        }
        localizeDoc(document,
                new FileSolutionFile(file, ((FileSolutionFile) getRootFolder(actionOperation)).getFile()));
        return document;
    }

    private File getFile(final IRuntimeContext runtimeContext, final String path) {
        if (runtimeContext == null) {
            error(Messages.getErrorString("SolutionRepository.ERROR_0002_NULL_RUNTIME_CONTEXT")); //$NON-NLS-1$
            return null;
        }
        File f = getFile(runtimeContext.getSolutionName() + File.separator + path, false);
        if (!f.exists()) {
            error(Messages.getErrorString("SolutionRepository.ERROR_0003_NULL_SOLUTION_FILE", path)); //$NON-NLS-1$
            return null;
        }
        // TODO: caching
        if (SolutionRepositoryBase.debug) {
            debug(Messages.getString("SolutionRepository.DEBUG_FILE_PATH", f.getAbsolutePath())); //$NON-NLS-1$
        }
        return f;
    }

    protected String getActionDefinition(final IRuntimeContext runtimeContext, final String actionPath) {
        // TODO: caching
        if ((runtimeContext == null) || (runtimeContext.getInstanceId() == null)
                || (runtimeContext.getActionName() == null)) {
            error(Messages.getErrorString("SolutionRepository.ERROR_0004_INVALID_CONTEXT")); //$NON-NLS-1$
        }
        genLogIdFromInfo(runtimeContext.getInstanceId(), SolutionRepositoryBase.LOG_NAME,
                runtimeContext.getActionName());
        File f = getFile(runtimeContext, actionPath);
        if (f == null) {
            error(Messages.getErrorString("SolutionRepository.ERROR_0005_INVALID_SOLUTION_FILE") + actionPath); //$NON-NLS-1$
        }
        return FileHelper.getStringFromFile(f);
    }

    protected Document getActionDefinitionDocument(final IRuntimeContext runtimeContext, final String actionPath) {
        // TODO: caching
        genLogIdFromInfo(runtimeContext.getInstanceId(), SolutionRepositoryBase.LOG_NAME,
                runtimeContext.getActionName());
        File f = getFile(runtimeContext, actionPath);
        if (f == null) {
            return null;
        }
        Document document = null;
        try {
            document = XmlDom4JHelper.getDocFromFile(f, this.getResourceLoader());
        } catch (Exception e) {
            error(Messages.getString("SolutionRepository.ERROR_0009_INVALID_DOCUMENT", actionPath), e); //$NON-NLS-1$
            return null;
        }
        return document;
    }

    // Old prototype code that needs to be redone somehow...
    public void reloadSolutionRepository(final IPentahoSession localSession, final int localLoggingLevel) {
        if (isCachingAvailable()) {
            File rootDir = getFile("", false); //$NON-NLS-1$
            Document repository = DocumentHelper.createDocument();
            Element rootNode = repository.addElement("repository"); //$NON-NLS-1$
            processDir(rootNode, rootDir, null, 0, ISolutionRepository.ACTION_ADMIN);
            resetRepository();
            putRepositoryObjectInCache(getRepositoryKey(), repository);
        }
    }

    protected void processDir(final Element parentNode, final File parentDir, final String solutionId, int pathIdx,
            final int actionOperation) {
        File files[] = parentDir.listFiles();
        for (File element : files) {
            if (!element.isDirectory()) {
                String fileName = element.getName();
                processFile(fileName, element, parentNode, solutionId, pathIdx, actionOperation);
            }
        }
        for (File element : files) {
            if (element.isDirectory() && (!element.getName().equalsIgnoreCase("system")) //$NON-NLS-1$
                    && (!element.getName().equalsIgnoreCase("CVS")) //$NON-NLS-1$
                    && (!element.getName().equalsIgnoreCase(".svn"))) { //$NON-NLS-1$
                Element dirNode = parentNode.addElement("file"); //$NON-NLS-1$
                dirNode.addAttribute("type", FileInfo.FILE_TYPE_FOLDER); //$NON-NLS-1$
                // TODO read this from the directory index file
                String thisSolution;
                String path = ""; //$NON-NLS-1$
                if (solutionId == null) {
                    thisSolution = element.getName();
                    pathIdx = rootPath.length() + File.separator.length() + thisSolution.length();
                } else {
                    thisSolution = solutionId;
                    path = element.getAbsolutePath().substring(pathIdx);
                    // windows \ characters in the path gets messy in urls, so
                    // switch them to /
                    path = path.replace('\\', '/');
                    dirNode.addElement("path").setText(path); //$NON-NLS-1$
                }
                File indexFile = new File(element, ISolutionRepository.INDEX_FILENAME);
                Document indexDoc = null;
                if (indexFile.exists()) {
                    indexDoc = getSolutionDocument(thisSolution, path, ISolutionRepository.INDEX_FILENAME,
                            actionOperation);
                }
                if (indexDoc != null) {
                    addIndexToRepository(indexDoc, element, dirNode, path, thisSolution);
                } else {
                    dirNode.addAttribute("visible", "false"); //$NON-NLS-1$ //$NON-NLS-2$
                    String dirName = element.getName();
                    dirNode.addAttribute("name", XmlHelper.encode(dirName)); //$NON-NLS-1$
                    dirNode.addElement("title").setText(dirName); //$NON-NLS-1$
                }
                processDir(dirNode, element, thisSolution, pathIdx, actionOperation);
            } else if ((solutionId == null)
                    && element.getName().equalsIgnoreCase(ISolutionRepository.INDEX_FILENAME)) {
                Document indexDoc = null;
                indexDoc = getSolutionDocument("", "", ISolutionRepository.INDEX_FILENAME, actionOperation); //$NON-NLS-1$ //$NON-NLS-2$
                if (indexDoc != null) {
                    addIndexToRepository(indexDoc, parentDir, parentNode, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
                }
            }
        }
    }

    protected void processFile(String fileName, File element, final Element parentNode, final String solutionId,
            int pathIdx, final int actionOperation) {
        if (fileName.equals("Entries") || fileName.equals("Repository") || fileName.equals("Root")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            // ignore any CVS files
            return;
        }
        int lastPoint = fileName.lastIndexOf('.');
        if (lastPoint == -1) {
            // ignore anything with no extension
            return;
        }
        String extension = fileName.substring(lastPoint + 1).toLowerCase();
        String solutionPath = element.getAbsolutePath().substring(rootPath.length());
        if ("url".equals(extension)) { //$NON-NLS-1$
            addUrlToRepository(element, parentNode, solutionPath, actionOperation);
        }
        boolean addFile = "xaction".equals(extension); //$NON-NLS-1$
        IPluginManager pluginManager = (IPluginManager) PentahoSystem.get(IPluginManager.class, getSession());
        if (pluginManager != null) {
            Set<String> types = pluginManager.getContentTypes();
            addFile |= types != null && types.contains(extension);
        }
        if (!addFile) {
            return;
        }
        String path = element.getAbsolutePath().substring(pathIdx);
        if (!path.equals(fileName)) {
            path = path.substring(0, path.length() - fileName.length() - 1);
            // windows \ characters in the path gets messy in urls, so
            // switch them to /
            path = path.replace('\\', '/');
        } else {
            path = ""; //$NON-NLS-1$
        }
        if (fileName.toLowerCase().endsWith(".xaction")) { //$NON-NLS-1$ 
            // create an action sequence document from this
            info(Messages.getString("SolutionRepository.DEBUG_ADDING_ACTION", fileName)); //$NON-NLS-1$
            IActionSequence actionSequence = getActionSequence(solutionId, path, fileName, loggingLevel,
                    actionOperation);
            if (actionSequence == null) {
                error(Messages.getErrorString("SolutionRepository.ERROR_0006_INVALID_SEQUENCE_DOCUMENT", fileName)); //$NON-NLS-1$
            } else {
                addToRepository(actionSequence, parentNode, element);
            }
        } else if (pluginManager != null) {
            String fullPath = solutionId + ISolutionRepository.SEPARATOR
                    + ((StringUtil.isEmpty(path)) ? "" : path + ISolutionRepository.SEPARATOR) + fileName; //$NON-NLS-1$
            try {
                IFileInfo fileInfo = getFileInfo(solutionId, path, fileName, extension, pluginManager,
                        ACTION_EXECUTE);
                addToRepository(fileInfo, solutionId, path, fileName, parentNode, element);
            } catch (Exception e) {
                error(Messages.getErrorString("SolutionRepository.ERROR_0021_FILE_NOT_ADDED", fullPath), e); //$NON-NLS-1$
            }
        }

    }

    private void addToRepository(final IFileInfo info, final String solution, final String path,
            final String fileName, final Element parentNode, final File file) {
        Element dirNode = parentNode.addElement("file"); //$NON-NLS-1$
        dirNode.addAttribute("type", FileInfo.FILE_TYPE_ACTIVITY); //$NON-NLS-1$
        dirNode.addElement("filename").setText(fileName); //$NON-NLS-1$
        dirNode.addElement("path").setText(path); //$NON-NLS-1$
        dirNode.addElement("solution").setText(solution); //$NON-NLS-1$
        dirNode.addElement("title").setText(info.getTitle()); //$NON-NLS-1$
        String description = info.getDescription();
        if (description == null) {
            dirNode.addElement("description"); //$NON-NLS-1$
        } else {
            dirNode.addElement("description").setText(description); //$NON-NLS-1$
        }
        String author = info.getAuthor();
        if (author == null) {
            dirNode.addElement("author"); //$NON-NLS-1$
        } else {
            dirNode.addElement("author").setText(author); //$NON-NLS-1$
        }
        String iconPath = info.getIcon();
        if ((iconPath != null) && !iconPath.equals("")) { //$NON-NLS-1$
            String rolloverIconPath = null;
            int rolloverIndex = iconPath.indexOf("|"); //$NON-NLS-1$
            if (rolloverIndex > -1) {
                rolloverIconPath = iconPath.substring(rolloverIndex + 1);
                iconPath = iconPath.substring(0, rolloverIndex);
            }
            if (publishIcon(file.getParentFile().getAbsolutePath(), iconPath)) {
                dirNode.addElement("icon").setText("getImage?image=icons/" + iconPath); //$NON-NLS-1$ //$NON-NLS-2$
            } else {
                dirNode.addElement("icon").setText(info.getIcon()); //$NON-NLS-1$
            }
            if (rolloverIconPath != null) {
                if (publishIcon(
                        PentahoSystem.getApplicationContext().getSolutionPath(solution + File.separator + path),
                        rolloverIconPath)) {
                    dirNode.addElement("rollovericon").setText("getImage?image=icons/" + rolloverIconPath); //$NON-NLS-1$ //$NON-NLS-2$
                } else {
                    dirNode.addElement("rollovericon").setText(rolloverIconPath); //$NON-NLS-1$
                }
            }
        }
        String displayType = info.getDisplayType();
        if ((displayType == null) || ("none".equalsIgnoreCase(displayType))) { //$NON-NLS-1$
            // this should be hidden from users
            dirNode.addAttribute("visible", "false"); //$NON-NLS-1$ //$NON-NLS-2$
        } else {
            dirNode.addAttribute("visible", "true"); //$NON-NLS-1$ //$NON-NLS-2$
            dirNode.addAttribute("displaytype", displayType); //$NON-NLS-1$
        }

        ISubscriptionRepository subscriptionRepository = PentahoSystem.get(ISubscriptionRepository.class,
                getSession());
        boolean subscribable = false;
        if (subscriptionRepository != null) {
            subscribable = subscriptionRepository.getContentByActionReference(solution
                    + ISolutionRepository.SEPARATOR + path + ISolutionRepository.SEPARATOR + fileName) != null;
        }
        dirNode.addElement("properties").setText("subscribable=" + Boolean.toString(subscribable)); //$NON-NLS-1$ //$NON-NLS-2$

    }

    // TODO sbarkdull, needs to be refactored, consider if
    // how it should work with/, etc. XmlHelper getLocalizedFile
    protected String getLocaleString(final String key, String baseName, final ISolutionFile baseFile) {
        File searchDir = ((FileSolutionFile) baseFile.retrieveParent()).getFile();
        try {
            boolean searching = true;
            while (searching) {
                // look to see if this exists
                URLClassLoader loader = new URLClassLoader(new URL[] { searchDir.toURL() }, null);
                String localeText = null;
                try {
                    ResourceBundle rb = ResourceBundle.getBundle(baseName, getLocale(), loader);
                    localeText = rb.getString(key.substring(1));
                } catch (Exception e) {
                    // couldn't load bundle, move along
                }
                if (localeText != null) {
                    return localeText;
                }
                // if we get to here, we couldn't use the resource bundle to find the string, so we will use this another approach
                // change the basename to messages (messages.properties) and go up a directory in our searching
                if (searching) {
                    if (!baseName.equals("messages")) { //$NON-NLS-1$
                        baseName = "messages"; //$NON-NLS-1$
                    } else {
                        if (searchDir.equals(rootFile)) {
                            searching = false;
                        } else {
                            searchDir = searchDir.getParentFile();
                        }
                    }
                }
            }
            return null;
        } catch (Exception e) {
            error(Messages.getErrorString("SolutionRepository.ERROR_0007_COULD_NOT_READ_PROPERTIES", //$NON-NLS-1$
                    baseFile.getFullPath()), e);
        }
        return null;
    }

    protected void addIndexToRepository(final Document indexDoc, final File directoryFile,
            final Element directoryNode, final String path, final String solution) {
        // TODO see if there is a localized attribute file for the current
        // locale
        String dirName = getValue(indexDoc, "/index/name", directoryFile.getName().replace('_', ' ')); //$NON-NLS-1$
        String description = getValue(indexDoc, "/index/description", ""); //$NON-NLS-1$ //$NON-NLS-2$
        String iconPath = getValue(indexDoc, "/index/icon", ""); //$NON-NLS-1$ //$NON-NLS-2$
        String displayType = getValue(indexDoc, "/index/display-type", "icons"); //$NON-NLS-1$ //$NON-NLS-2$
        boolean visible = getValue(indexDoc, "/index/visible", "false").equalsIgnoreCase("true"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

        if (solution == null) {
            directoryNode.addAttribute("name", solution); //$NON-NLS-1$
        } else {
            directoryNode.addAttribute("name", XmlHelper.encode(directoryFile.getName())); //$NON-NLS-1$
        }
        directoryNode.addElement("title").setText(dirName); //$NON-NLS-1$
        // directoryNode.addElement( "path" ).setText( path ); //$NON-NLS-1$
        directoryNode.addAttribute("path", XmlHelper.encode(path)); //$NON-NLS-1$
        directoryNode.addElement("description").setText(description); //$NON-NLS-1$
        if (!StringUtil.isEmpty(iconPath)) {
            String rolloverIconPath = null;
            int rolloverIndex = iconPath.indexOf("|"); //$NON-NLS-1$
            if (rolloverIndex > -1) {
                rolloverIconPath = iconPath.substring(rolloverIndex + 1);
                iconPath = iconPath.substring(0, rolloverIndex);
            }
            if (publishIcon(PentahoSystem.getApplicationContext().getSolutionPath(solution + File.separator + path),
                    iconPath)) {
                directoryNode.addElement("icon").setText("getImage?image=icons/" + iconPath); //$NON-NLS-1$ //$NON-NLS-2$
            } else {
                directoryNode.addElement("icon").setText(iconPath); //$NON-NLS-1$
            }
            if (rolloverIconPath != null) {
                if (publishIcon(
                        PentahoSystem.getApplicationContext().getSolutionPath(solution + File.separator + path),
                        rolloverIconPath)) {
                    directoryNode.addElement("rollovericon").setText("getImage?image=icons/" + rolloverIconPath); //$NON-NLS-1$ //$NON-NLS-2$
                } else {
                    directoryNode.addElement("rollovericon").setText(rolloverIconPath); //$NON-NLS-1$
                }
            }
        }
        directoryNode.addAttribute("visible", Boolean.toString(visible)); //$NON-NLS-1$
        directoryNode.addAttribute("displaytype", displayType); //$NON-NLS-1$
        directoryNode.addElement("solution").setText(solution); //$NON-NLS-1$
    }

    protected void addUrlToRepository(final File file, final Element parentNode, final String solutionPath,
            final int actionOperation) {
        // parse the .url file to get the contents
        ActionResource urlResource = new ActionResource(file.getName(),
                IActionSequenceResource.SOLUTION_FILE_RESOURCE, "text/url", solutionPath); //$NON-NLS-1$
        try {
            String urlContent = getResourceAsString(urlResource, actionOperation);
            StringTokenizer tokenizer = new StringTokenizer(urlContent, "\n"); //$NON-NLS-1$
            String url = null;
            String title = file.getName();
            String description = null;
            String iconPath = null;
            String target = null;
            while (tokenizer.hasMoreTokens()) {
                String line = tokenizer.nextToken();
                int pos = line.indexOf('=');
                if (pos > 0) {
                    String name = line.substring(0, pos);
                    String value = line.substring(pos + 1);
                    if ((value != null) && (value.length() > 0) && (value.charAt(value.length() - 1) == '\r')) {
                        value = value.substring(0, value.length() - 1);
                    }
                    if ("URL".equalsIgnoreCase(name)) { //$NON-NLS-1$
                        url = value;
                    }
                    if ("name".equalsIgnoreCase(name)) { //$NON-NLS-1$
                        title = value;
                    }
                    if ("description".equalsIgnoreCase(name)) { //$NON-NLS-1$
                        description = value;
                    }
                    if ("icon".equalsIgnoreCase(name)) { //$NON-NLS-1$
                        iconPath = value;
                    }
                    if ("target".equalsIgnoreCase(name)) { //$NON-NLS-1$
                        target = value;
                    }
                }
            }
            if (url != null) {
                // now create an entry for the database
                Element dirNode = parentNode.addElement("file"); //$NON-NLS-1$
                dirNode.addAttribute("type", FileInfo.FILE_TYPE_URL); //$NON-NLS-1$
                dirNode.addElement("filename").setText(file.getName()); //$NON-NLS-1$
                dirNode.addElement("title").setText(title); //$NON-NLS-1$
                if (target != null) {
                    dirNode.addElement("target").setText(target); //$NON-NLS-1$
                }
                if (description != null) {
                    dirNode.addElement("description").setText(description); //$NON-NLS-1$
                }
                if ((iconPath != null) && !iconPath.equals("")) { //$NON-NLS-1$
                    String rolloverIconPath = null;
                    int rolloverIndex = iconPath.indexOf("|"); //$NON-NLS-1$
                    if (rolloverIndex > -1) {
                        rolloverIconPath = iconPath.substring(rolloverIndex + 1);
                        iconPath = iconPath.substring(0, rolloverIndex);
                    }
                    if (publishIcon(file.getParentFile().getAbsolutePath(), iconPath)) {
                        dirNode.addElement("icon").setText("getImage?image=icons/" + iconPath); //$NON-NLS-1$ //$NON-NLS-2$
                    } else {
                        dirNode.addElement("icon").setText(iconPath); //$NON-NLS-1$
                    }
                    if (rolloverIconPath != null) {
                        if (publishIcon(PentahoSystem.getApplicationContext().getSolutionPath(solutionPath),
                                rolloverIconPath)) {
                            dirNode.addElement("rollovericon").setText("getImage?image=icons/" + rolloverIconPath); //$NON-NLS-1$ //$NON-NLS-2$
                        } else {
                            dirNode.addElement("rollovericon").setText(rolloverIconPath); //$NON-NLS-1$
                        }
                    }
                }
                dirNode.addElement("url").setText(url); //$NON-NLS-1$
                dirNode.addAttribute("visible", "true"); //$NON-NLS-1$ //$NON-NLS-2$
                dirNode.addAttribute("displaytype", FileInfo.FILE_DISPLAY_TYPE_URL); //$NON-NLS-1$
                localizeDoc(dirNode,
                        new FileSolutionFile(file, ((FileSolutionFile) getRootFolder(actionOperation)).getFile()));
            }
        } catch (IOException e) {
        }
    }

    protected void addToRepository(final IActionSequence actionSequence, final Element parentNode,
            final File file) {
        Element dirNode = parentNode.addElement("file"); //$NON-NLS-1$
        dirNode.addAttribute("type", FileInfo.FILE_TYPE_ACTIVITY); //$NON-NLS-1$
        if ((actionSequence.getSequenceName() == null) || (actionSequence.getSolutionPath() == null)
                || (actionSequence.getSolutionName() == null)) {
            error(Messages.getString("SolutionRepository.ERROR_0008_ACTION_SEQUENCE_NAME_INVALID")); //$NON-NLS-1$
            return;
        }
        dirNode.addElement("filename").setText(actionSequence.getSequenceName()); //$NON-NLS-1$
        dirNode.addElement("path").setText(actionSequence.getSolutionPath()); //$NON-NLS-1$
        dirNode.addElement("solution").setText(actionSequence.getSolutionName()); //$NON-NLS-1$
        String title = actionSequence.getTitle();
        if (title == null) {
            dirNode.addElement("title").setText(actionSequence.getSequenceName()); //$NON-NLS-1$
        } else {
            dirNode.addElement("title").setText(title); //$NON-NLS-1$
        }
        String description = actionSequence.getDescription();
        if (description == null) {
            dirNode.addElement("description"); //$NON-NLS-1$
        } else {
            dirNode.addElement("description").setText(description); //$NON-NLS-1$
        }
        String author = actionSequence.getAuthor();
        if (author == null) {
            dirNode.addElement("author"); //$NON-NLS-1$
        } else {
            dirNode.addElement("author").setText(author); //$NON-NLS-1$
        }
        String iconPath = actionSequence.getIcon();
        if ((iconPath != null) && !iconPath.equals("")) { //$NON-NLS-1$
            String rolloverIconPath = null;
            int rolloverIndex = iconPath.indexOf("|"); //$NON-NLS-1$
            if (rolloverIndex > -1) {
                rolloverIconPath = iconPath.substring(rolloverIndex + 1);
                iconPath = iconPath.substring(0, rolloverIndex);
            }
            if (publishIcon(file.getParentFile().getAbsolutePath(), iconPath)) {
                dirNode.addElement("icon").setText("getImage?image=icons/" + iconPath); //$NON-NLS-1$ //$NON-NLS-2$
            } else {
                dirNode.addElement("icon").setText(actionSequence.getIcon()); //$NON-NLS-1$
            }
            if (rolloverIconPath != null) {
                if (publishIcon(PentahoSystem.getApplicationContext().getSolutionPath(
                        actionSequence.getSolutionName() + File.separator + actionSequence.getSolutionPath()),
                        rolloverIconPath)) {
                    dirNode.addElement("rollovericon").setText("getImage?image=icons/" + rolloverIconPath); //$NON-NLS-1$ //$NON-NLS-2$
                } else {
                    dirNode.addElement("rollovericon").setText(rolloverIconPath); //$NON-NLS-1$
                }
            }
        }
        String displayType = actionSequence.getResultType();
        if ((displayType == null) || ("none".equalsIgnoreCase(displayType))) { //$NON-NLS-1$
            // this should be hidden from users
            dirNode.addAttribute("visible", "false"); //$NON-NLS-1$ //$NON-NLS-2$
        } else {
            dirNode.addAttribute("visible", "true"); //$NON-NLS-1$ //$NON-NLS-2$
            dirNode.addAttribute("displaytype", displayType); //$NON-NLS-1$
        }

        ISubscriptionRepository subscriptionRepository = PentahoSystem.get(ISubscriptionRepository.class,
                getSession());
        boolean subscribable = false;
        if (subscriptionRepository != null) {
            subscribable = subscriptionRepository.getContentByActionReference(actionSequence.getSolutionName() + '/'
                    + actionSequence.getSolutionPath() + '/' + actionSequence.getSequenceName()) != null;
        }
        dirNode.addElement("properties").setText("subscribable=" + Boolean.toString(subscribable)); //$NON-NLS-1$ //$NON-NLS-2$

    }

    protected boolean publishIcon(final String dirPath, final String iconPath) {
        File iconSource = new File(dirPath + File.separator + iconPath);
        if (iconSource.exists()) {
            File tmpDir = getFile("system/tmp/icons", true); //$NON-NLS-1$
            tmpDir.mkdirs();
            File iconDestintation = new File(tmpDir.getAbsoluteFile() + File.separator + iconPath);
            if (iconDestintation.exists()) {
                iconDestintation.delete();
            }
            try {
                InputStream stream = new BufferedInputStream(new FileInputStream(iconSource));
                OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(iconDestintation));
                try {
                    IOUtils.copy(stream, outputStream);
                } finally {
                    outputStream.close();
                    stream.close();
                }
            } catch (FileNotFoundException e) {
                // this one is not very likey
                error(e.getLocalizedMessage());
            } catch (IOException e) {
                error(e.getLocalizedMessage());
            }
            return true;
        } else {
            return false;
        }
    }

    public Document getSolutions(final String solutionName, final String pathName, final int actionOperation,
            final boolean visibleOnly) {
        return getSolutions(actionOperation);
    }

    @Override
    public Document getSolutions(final int actionOperation) {
        Object cachedRepo = getRepositoryObjectFromCache(getRepositoryKey());
        if (cachedRepo == null) {
            reloadSolutionRepository(getSession(), loggingLevel);
            cachedRepo = getRepositoryObjectFromCache(getRepositoryKey());
        }
        return (Document) cachedRepo;
    }

    private Document getActionSequences(final String solution, final String path, final boolean subDirectories,
            final boolean visibleOnly, final int actionOperation) {
        List nodes;
        if (solution == null) {
            nodes = getSolutionNames(solution, path, actionOperation, visibleOnly);
        } else {
            nodes = getFileListIterator(solution, path, subDirectories, visibleOnly);
        }
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("files"); //$NON-NLS-1$
        Element pathNames = root.addElement("location"); //$NON-NLS-1$

        pathNames.setText(getPathNames(solution, path));

        Iterator nodeIterator = nodes.iterator();
        while (nodeIterator.hasNext()) {
            Node node = (Node) nodeIterator.next();
            root.add((Node) node.clone());
        }
        return document;
    }

    private String getPathNames(final String solutionId, final String path) {
        Document repository = (Document) getRepositoryObjectFromCache(getRepositoryKey());
        if (repository == null) {
            reloadSolutionRepository(getSession(), loggingLevel);
            repository = (Document) getRepositoryObjectFromCache(getRepositoryKey());
        }
        if (solutionId == null) {
            return ""; //$NON-NLS-1$
        }

        // TODO sbarkdull, extract to a method, this same code is repeated in this class
        String xPath = "/repository/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"][@name=\"" //$NON-NLS-1$//$NON-NLS-2$
                + XmlHelper.encode(solutionId) + "\"]"; //$NON-NLS-1$

        if (path != null) {
            String folders[] = path.split("/"); //$NON-NLS-1$
            if (folders != null) {
                for (String element : folders) {
                    xPath += "/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"][@name=\"" //$NON-NLS-1$//$NON-NLS-2$
                            + XmlHelper.encode(element) + "\"]"; //$NON-NLS-1$
                    xPath += "[@visible=\"true\"]"; //$NON-NLS-1$
                }
            }
        }

        StringBuffer sb = new StringBuffer();
        List list = repository.selectNodes(xPath);
        if ((list != null) && (list.size() > 0)) {
            // grab the first one
            Element node = (Element) list.get(0);
            // walk up the ancestors
            boolean done = false;
            while ((node != null) && !done) {
                Node titleNode = node.selectSingleNode("title"); //$NON-NLS-1$
                if (titleNode != null) {
                    String name = titleNode.getText();
                    sb.insert(0, name + "/"); //$NON-NLS-1$
                } else {
                    // if we don't have a title node then there is nothing more we can do to construct the path
                    done = true;
                }
                node = node.getParent();
            }
        }
        return sb.toString();

    }

    private List getFileListIterator(final String solutionId, final String path, final boolean subDirectories,
            final boolean visibleOnly) {
        Document repository = (Document) getRepositoryObjectFromCache(getRepositoryKey());
        if (repository == null) {
            reloadSolutionRepository(getSession(), loggingLevel);
            repository = (Document) getRepositoryObjectFromCache(getRepositoryKey());
        }
        String xPath;
        if (solutionId == null) {
            xPath = "/repository/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$
        } else {
            xPath = "/repository/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"][@name=\"" //$NON-NLS-1$//$NON-NLS-2$
                    + XmlHelper.encode(solutionId) + "\"]"; //$NON-NLS-1$
        }
        if (path != null) {
            String folders[] = path.split("/"); //$NON-NLS-1$
            if (folders != null) {
                for (String element : folders) {
                    xPath += "/file[@type=\"" + FileInfo.FILE_TYPE_FOLDER + "\"][@name=\"" //$NON-NLS-1$//$NON-NLS-2$
                            + XmlHelper.encode(element) + "\"]"; //$NON-NLS-1$
                    if (visibleOnly) {
                        xPath += "[@visible=\"true\"]"; //$NON-NLS-1$
                    }
                }
            }
        }
        if (subDirectories) {
            xPath = "descendant-or-self::" + xPath; //$NON-NLS-1$
        }
        if (SolutionRepositoryBase.debug) {
            debug(Messages.getString("SolutionRepository.DEBUG_FILE_LIST_XPATH", xPath)); //$NON-NLS-1$
        }
        return repository.selectNodes(xPath);
    }

    public Document getSolutionStructure(final int actionOperation) {
        Document document = DocumentHelper.createDocument();
        File rootDir = getFile(SolutionRepositoryBase.EMPTY_STR, false);
        Element root = document.addElement(SolutionRepositoryBase.ROOT_NODE_NAME)
                .addAttribute(SolutionRepositoryBase.LOCATION_ATTR_NAME, rootDir.getAbsolutePath());
        processSolutionTree(root, rootDir);
        return document;
    }

    public Document getSolutionTree(final int actionOperation, final ISolutionFilter filter) {
        // create a document to return
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement(SolutionReposHelper.TREE_NODE_NAME);
        // process the tree using the filter provided as a parameter
        SolutionReposHelper.processSolutionTree(root, new FileSolutionFile(rootFile, rootFile), filter,
                actionOperation);
        return document;
    }

    public Document getSolutionTree(final int actionOperation) {
        return getSolutionTree(actionOperation, defaultSolutionFilter);
    }

    private void processSolutionTree(final Element parentNode, final File targetFile) {
        if (targetFile.isDirectory()) {
            if (!SolutionReposHelper.ignoreDirectory(targetFile.getName())) {
                Element childNode = parentNode.addElement(SolutionReposHelper.ENTRY_NODE_NAME)
                        .addAttribute(SolutionReposHelper.TYPE_ATTR_NAME, SolutionReposHelper.DIRECTORY_ATTR)
                        .addAttribute(SolutionReposHelper.NAME_ATTR_NAME, targetFile.getName());
                File files[] = targetFile.listFiles();
                for (File file : files) {
                    processSolutionTree(childNode, file);
                }
            }
        } else {
            if (!targetFile.isHidden() && !SolutionReposHelper.ignoreFile(targetFile.getName())) {
                parentNode.addElement(SolutionReposHelper.ENTRY_NODE_NAME)
                        .addAttribute(SolutionReposHelper.TYPE_ATTR_NAME, SolutionReposHelper.FILE_ATTR)
                        .addAttribute(SolutionReposHelper.NAME_ATTR_NAME, targetFile.getName());
            }
        }
    }

    // -----------------------------------------------------------------------
    // Methods from PentahoSystem
    public boolean resourceExists(final String solutionPath, final int actionOperation) {
        String filePath = PentahoSystem.getApplicationContext().getSolutionPath(solutionPath);
        File file = new File(filePath);
        return file.exists();
    }

    public long resourceSize(final String solutionPath, final int actionOperation) {
        if (!resourceExists(solutionPath, actionOperation)) {
            return -1;
        }
        String filePath = PentahoSystem.getApplicationContext().getSolutionPath(solutionPath);
        File file = new File(filePath);
        return file.length();
    }

    public String[] getAllActionSequences(final int actionOperation) {
        File rootDir = getFile("", false); //$NON-NLS-1$
        List files = new ArrayList();
        files = getAllActionSequences(rootDir, files);
        String[] value = new String[files.size()];
        Iterator iter = files.iterator();
        int i = 0;
        int solutionPathOffset = PentahoSystem.getApplicationContext().getSolutionPath("").length(); //$NON-NLS-1$
        while (iter.hasNext()) {
            File file = (File) iter.next();
            String filePath = file.getAbsolutePath();
            filePath = filePath.substring(solutionPathOffset);
            filePath = filePath.replace('\\', '/');
            value[i++] = filePath;
        }
        return value;
    }

    private List getAllActionSequences(final File rootDir, final List files) {
        if (!rootDir.isDirectory()) {
            return files;
        }
        File[] fileArray = rootDir.listFiles(new xActionFileFilter());
        for (File element : fileArray) {
            files.add(element);
        }
        fileArray = rootDir.listFiles();
        for (File element : fileArray) {
            if (element.isDirectory()) {
                getAllActionSequences(element, files);
            }
        }
        return files;
    }

    public long getSolutionFileLastModified(final String path, final int actionOperation) {
        File file = getFile(path, false);
        long mod = -1;
        if (file != null) {
            mod = file.lastModified();
        }
        return mod;
    }

    class xActionFileFilter implements FilenameFilter {
        public boolean accept(final File dir, final String name) {
            int seperatorIndex = name.lastIndexOf('.');
            if (seperatorIndex != -1) {
                return name.substring(name.lastIndexOf('.')).equalsIgnoreCase(".xaction"); //$NON-NLS-1$
            }
            return false;
        }
    }

    @Override
    public Document getNavigationUIDocument(final String solution, final String path, final int actionOperation) {
        Document document = null;
        if (StringUtil.isEmpty(solution)) {
            document = this.getSolutions(ISolutionRepository.ACTION_EXECUTE);
        } else {
            document = getActionSequences(solution, path, false, true, ISolutionRepository.ACTION_EXECUTE);
        }
        return document;
    }

    public String getRepositoryName() {
        return "";//$NON-NLS-1$
    }

    public boolean supportsAccessControls() {
        return false;
    }

    private String getRepositoryKey() {
        return "repository" + getLocale().toString();//$NON-NLS-1$
    }

    /**
     * No access control is enforced in this implementation.
     * @see supportsAccessControls
     */
    public boolean hasAccess(final ISolutionFile file, final int actionOperation) {
        return true;
    }

    public int publish(final String baseUrl, final String path, final String fileName, final byte[] data,
            final boolean overwrite) throws PentahoAccessControlException {
        return addSolutionFile(baseUrl, path, fileName, data, overwrite);
    }

    public int publish(final String baseUrl, final String path, final String fileName, final File f,
            final boolean overwrite) throws PentahoAccessControlException {
        return addSolutionFile(baseUrl, path, fileName, f, overwrite);
    }

    public void share(final ISolutionFile file, final List<IPermissionRecipient> shareRecipient) {
    }

    public void addPermission(final ISolutionFile file, final IPermissionRecipient recipient,
            final IPermissionMask permission) {
    }

    public void setPermissions(final ISolutionFile file, final Map<IPermissionRecipient, IPermissionMask> acl)
            throws PentahoAccessControlException {
    }

    public Map<IPermissionRecipient, IPermissionMask> getPermissions(final ISolutionFile file) {
        return Collections.emptyMap();
    }

    public Map<IPermissionRecipient, IPermissionMask> getEffectivePermissions(final ISolutionFile file) {
        return Collections.emptyMap();
    }

    public boolean synchronizeSolutionWithSolutionSource(final IPentahoSession pSession) {
        throw new UnsupportedOperationException("Synchronization is not supported by this implementor"); //$NON-NLS-1$
    }

    public boolean solutionSynchronizationSupported() {
        return false;
    }

    private class DefaultSolutionFilter implements ISolutionFilter {
        public boolean keepFile(final ISolutionFile solutionFile, final int actionOperation) {
            // No filtering of solution files/folders in the file-based repository
            // yet.
            return true;
        }
    }
}