/*
* 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.getInstance().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.getInstance().getErrorString("SolutionRepository.ERROR_0016_FAILED_TO_CREATE_ACTION_SEQUENCE", action)); //$NON-NLS-1$
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.getInstance().getErrorString("SolutionRepository.ERROR_0001_FILE_DOES_NOT_EXIST", documentPath)); //$NON-NLS-1$
return null;
} else {
if (!file.exists()) {
error(Messages.getInstance().getErrorString("SolutionRepository.ERROR_0001_FILE_DOES_NOT_EXIST", documentPath)); //$NON-NLS-1$
return null;
} else if (!file.canRead()) {
error(Messages.getInstance().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.getInstance().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.getInstance().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.getInstance().getErrorString("SolutionRepository.ERROR_0003_NULL_SOLUTION_FILE", path)); //$NON-NLS-1$
return null;
}
// TODO: caching
if (SolutionRepositoryBase.debug) {
debug(Messages.getInstance().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.getInstance().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.getInstance().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.getInstance().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")) && (!element.getName().equalsIgnoreCase("CVS")) && (!element.getName().equalsIgnoreCase(".svn"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
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.getInstance().getString("SolutionRepository.DEBUG_ADDING_ACTION", fileName)); //$NON-NLS-1$
IActionSequence actionSequence = getActionSequence(solutionId, path, fileName, loggingLevel, actionOperation);
if (actionSequence == null) {
error(Messages.getInstance().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.getInstance().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.getInstance().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.getInstance().getErrorString("SolutionRepository.ERROR_0007_COULD_NOT_READ_PROPERTIES", baseFile.getFullPath()), e); //$NON-NLS-1$
}
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.getInstance().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=\"" + XmlHelper.encode(solutionId) + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
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=\"" + XmlHelper.encode(element) + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
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=\"" + XmlHelper.encode(solutionId) + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
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=\"" + XmlHelper.encode(element) + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (visibleOnly) {
xPath += "[@visible=\"true\"]"; //$NON-NLS-1$
}
}
}
}
if (subDirectories) {
xPath = "descendant-or-self::" + xPath; //$NON-NLS-1$
}
if (SolutionRepositoryBase.debug) {
debug(Messages.getInstance().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;
}
}
}