/* * 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 2006 - 2013 Pentaho Corporation. All rights reserved. */ package org.pentaho.platform.engine.services; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.Document; import org.dom4j.Node; import org.pentaho.platform.api.engine.IActionSequence; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.repository2.unified.IFileFilter; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.api.repository2.unified.RepositoryFilePermission; import org.pentaho.platform.api.repository2.unified.data.simple.SimpleRepositoryFileData; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.services.actionsequence.SequenceDefinition; import org.pentaho.platform.engine.services.messages.Messages; import org.pentaho.platform.util.messages.LocaleHelper; import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.StringTokenizer; /** * @author wseyler * */ public class ActionSequenceJCRHelper { protected static final String PROPERTIES_SUFFIX = ".properties"; //$NON-NLS-1$ protected static final Log logger = LogFactory.getLog( ActionSequenceJCRHelper.class ); private IPentahoSession pentahoSession; private IUnifiedRepository repository; public ActionSequenceJCRHelper() { this( PentahoSessionHolder.getSession() ); } public ActionSequenceJCRHelper( IPentahoSession pentahoSession ) { super(); assert pentahoSession != null; this.pentahoSession = pentahoSession; repository = PentahoSystem.get( IUnifiedRepository.class, pentahoSession ); if ( repository == null ) { final String errorMessage = Messages.getInstance().getErrorString( "ActionSequenceJCRHelper.ERROR_0001_INVALID_REPOSITORY" ); //$NON-NLS-1$ logger.error( errorMessage ); throw new IllegalStateException( errorMessage ); } } /** * This legacy method ignores the requested actionOperation and defines read as the permission. * * @deprecated use getActionSequence(String actionPath, int loggingLevel, RepositoryFilePermission * actionOperation) instead. */ @Deprecated public IActionSequence getActionSequence( String actionPath, int loggingLevel, int actionOperation ) { return getActionSequence( actionPath, loggingLevel, RepositoryFilePermission.READ ); } public IActionSequence getActionSequence( String actionPath, int loggingLevel, RepositoryFilePermission actionOperation ) { Document actionSequenceDocument = getSolutionDocument( actionPath, actionOperation ); if ( actionSequenceDocument == null ) { return null; } IActionSequence actionSequence = SequenceDefinition.ActionSequenceFactory( actionSequenceDocument, actionPath, pentahoSession, PentahoSystem .getApplicationContext(), loggingLevel ); if ( actionSequence == null ) { return null; } return actionSequence; } public Document getSolutionDocument( final String documentPath, final RepositoryFilePermission actionOperation ) { RepositoryFile file = repository.getFile( documentPath ); Document document = null; SimpleRepositoryFileData data = null; if ( file != null ) { data = repository.getDataForRead( file.getId(), SimpleRepositoryFileData.class ); if ( data != null ) { try { document = XmlDom4JHelper.getDocFromStream( data.getStream() ); } catch ( Throwable t ) { logger.error( Messages.getInstance().getErrorString( "ActionSequenceJCRHelper.ERROR_0017_INVALID_XML_DOCUMENT", documentPath ), t ); //$NON-NLS-1$ return null; } } else { logger.error( Messages.getInstance().getErrorString( "ActionSequenceJCRHelper.ERROR_0019_NO_DATA_IN_FILE", file.getName() ) ); //$NON-NLS-1$ return null; } if ( ( document == null ) && ( file != null ) && ( data != null ) ) { // the document exists but cannot be parsed logger.error( Messages.getInstance().getErrorString( "ActionSequenceJCRHelper.ERROR_0009_INVALID_DOCUMENT", documentPath ) ); //$NON-NLS-1$ return null; } localizeDoc( document, file ); } return document; } public String getURL( String filePath ) { RepositoryFile file = repository.getFile( filePath ); if ( file == null || !file.getName().endsWith( ".url" ) ) { //$NON-NLS-1$ return ""; //$NON-NLS-1$ } SimpleRepositoryFileData data = null; data = repository.getDataForRead( file.getId(), SimpleRepositoryFileData.class ); StringWriter writer = new StringWriter(); try { IOUtils.copy( data.getStream(), writer ); } catch ( IOException e ) { return ""; //$NON-NLS-1$ } String props = writer.toString(); StringTokenizer tokenizer = new StringTokenizer( props, "\n" ); //$NON-NLS-1$ while ( tokenizer.hasMoreTokens() ) { String line = tokenizer.nextToken(); int pos = line.indexOf( '=' ); if ( pos > 0 ) { String propname = 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( propname ) ) { //$NON-NLS-1$ return value; } } } // No URL found return ""; } public void localizeDoc( final Node document, final RepositoryFile file ) { String fileName = file.getName(); int dotIndex = fileName.indexOf( '.' ); String baseName = fileName.substring( 0, dotIndex ); // TODO read in nodes from the locale file and use them to override the // ones in the main document try { List nodes = document.selectNodes( "descendant::*" ); //$NON-NLS-1$ Iterator nodeIterator = nodes.iterator(); while ( nodeIterator.hasNext() ) { Node node = (Node) nodeIterator.next(); String name = node.getText(); if ( name.startsWith( "%" ) && !node.getPath().endsWith( "/text()" ) ) { //$NON-NLS-1$ //$NON-NLS-2$ try { String localeText = getLocaleString( name, baseName, file, true ); if ( localeText != null ) { node.setText( localeText ); } } catch ( Exception e ) { logger .warn( Messages .getInstance() .getString( "ActionSequenceJCRHelper.WARN_MISSING_RESOURCE_PROPERTY", name.substring( 1 ), baseName, getLocale().toString() ) ); //$NON-NLS-1$ } } } } catch ( Exception e ) { logger.error( Messages.getInstance().getErrorString( "ActionSequenceJCRHelper.ERROR_0007_COULD_NOT_READ_PROPERTIES", file.getPath() ), e ); //$NON-NLS-1$ } } protected String getLocaleString( final String key, String baseName, final RepositoryFile baseFile, boolean marchUpParents ) { String parentPath = FilenameUtils.getFullPathNoEndSeparator( baseFile.getPath() ); RepositoryFile searchDir = repository.getFile( parentPath ); if ( baseFile.isFolder() ) { searchDir = baseFile; } try { boolean searching = true; while ( searching ) { RepositoryFile[] propertyFiles = listFiles( searchDir, new IFileFilter() { public boolean accept( RepositoryFile file ) { return file.getName().toLowerCase().endsWith( PROPERTIES_SUFFIX ); } } ); RepositoryFile blcv = null; RepositoryFile blc = null; RepositoryFile bl = null; RepositoryFile b = null; for ( RepositoryFile element : propertyFiles ) { if ( element.getName().equalsIgnoreCase( baseName + '_' + getLocale().getLanguage() + '_' + getLocale().getCountry() + '_' + getLocale().getVariant() + PROPERTIES_SUFFIX ) ) { blcv = element; } if ( element.getName().equalsIgnoreCase( baseName + '_' + getLocale().getLanguage() + '_' + getLocale().getCountry() + PROPERTIES_SUFFIX ) ) { blc = element; } if ( element.getName().equalsIgnoreCase( baseName + '_' + getLocale().getLanguage() + PROPERTIES_SUFFIX ) ) { bl = element; } if ( element.getName().equalsIgnoreCase( baseName + PROPERTIES_SUFFIX ) ) { b = element; } } String localeText = getLocaleText( key, blcv ); if ( localeText == null ) { localeText = getLocaleText( key, blc ); if ( localeText == null ) { localeText = getLocaleText( key, bl ); if ( localeText == null ) { localeText = getLocaleText( key, b ); } } } if ( localeText != null ) { return localeText; } if ( searching && marchUpParents ) { if ( !baseName.equals( "messages" ) ) { //$NON-NLS-1$ baseName = "messages"; //$NON-NLS-1$ } else { parentPath = FilenameUtils.getFullPathNoEndSeparator( searchDir.getPath() ); // If the parent path is empty or the same as the parent's parent path (meaning root) if ( parentPath == null || parentPath.length() < 1 || parentPath.equals( searchDir.getPath() ) ) { searching = false; } else { searchDir = repository.getFile( parentPath ); } } } else if ( !marchUpParents ) { searching = false; } } return null; } catch ( Exception e ) { logger.error( Messages.getInstance().getErrorString( "ActionSequenceJCRHelper.ERROR_0007_COULD_NOT_READ_PROPERTIES", baseFile.getPath() ), e ); //$NON-NLS-1$ } return null; } protected Locale getLocale() { return LocaleHelper.getLocale(); } protected String getLocaleText( final String key, final RepositoryFile file ) throws IOException { if ( file != null ) { SimpleRepositoryFileData data = null; data = repository.getDataForRead( file.getId(), SimpleRepositoryFileData.class ); Properties p = new Properties(); p.load( data.getStream() ); String localeText = p.getProperty( key.substring( 1 ) ); if ( localeText == null ) { localeText = p.getProperty( key ); } if ( localeText != null ) { return localeText; } } return null; } private RepositoryFile[] listFiles( RepositoryFile searchDir, final IFileFilter filter ) { List<RepositoryFile> matchedFiles = new ArrayList<RepositoryFile>(); Object[] objArray = repository.getChildren( searchDir.getId() ).toArray(); for ( Object element : objArray ) { if ( filter.accept( (RepositoryFile) element ) ) { matchedFiles.add( (RepositoryFile) element ); } } return matchedFiles.toArray( new RepositoryFile[] {} ); } }