/*
* 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 - 2017 Pentaho Corporation. All rights reserved.
*/
package org.pentaho.platform.repository.solution.filebased;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.vfs2.FileContent;
import org.apache.commons.vfs2.FileName;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSelector;
import org.apache.commons.vfs2.FileSystem;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileType;
import org.apache.commons.vfs2.NameScope;
import org.apache.commons.vfs2.operations.FileOperations;
import org.pentaho.platform.api.repository2.unified.Converter;
import org.pentaho.platform.api.repository2.unified.IRepositoryContentConverterHandler;
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.UnifiedRepositoryException;
import org.pentaho.platform.api.repository2.unified.data.simple.SimpleRepositoryFileData;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.api.repository2.unified.IAclNodeHelper;
import org.pentaho.platform.repository2.unified.jcr.JcrAclNodeHelper;
public class SolutionRepositoryVfsFileObject implements FileObject {
private static IAclNodeHelper testAclHelper;
private String fileRef;
private static final IUnifiedRepository repository = PentahoSystem.get( IUnifiedRepository.class, null );
private FileContent content = null;
private RepositoryFile repositoryFile = null;
private IRepositoryContentConverterHandler converterHandler;
private IAclNodeHelper aclHelper;
public SolutionRepositoryVfsFileObject( final String fileRef ) {
super();
this.fileRef = fileRef;
}
public IUnifiedRepository getRepository() {
return repository;
}
public IRepositoryContentConverterHandler getConverterHandler() {
if ( converterHandler == null ) {
converterHandler = PentahoSystem.get( IRepositoryContentConverterHandler.class );
}
return converterHandler;
}
public String getFileRef() {
return fileRef;
}
public FileName getName() {
initFile();
FileType fileType = null;
try {
fileType = getType();
} catch ( Exception ex ) {
fileType = FileType.FOLDER;
}
return new SolutionRepositoryFileName( fileRef, fileType );
}
/**
* TODO: This impl always returns null as the URL constructor throws an exception on not finding a handler for 'solution' protocol
* We should either fix this or remove this method as it is not called by any code
* @return
* @throws FileSystemException
*/
public URL getURL() throws FileSystemException {
URL url = null;
try {
url = new URL( "solution:" + fileRef ); //$NON-NLS-1$
} catch ( Exception e ) {
// CHECKSTYLES IGNORE
}
return url;
}
private void initFile() {
// decode URL before 'get'
String fileUrl = fileRef;
try {
final Charset urlCharset = Charset.forName( "UTF-8" );
fileUrl = URLDecoder.decode( fileUrl, urlCharset.name() );
} catch ( UnsupportedEncodingException e ) {
fileUrl = fileRef;
}
String dsPath = fileUrl;
if ( fileUrl.matches( "^(/etc/mondrian/)(.*)(/schema.xml)" ) ) {
dsPath = fileUrl.substring( 0, fileUrl.indexOf( "/schema.xml" ) );
}
repositoryFile = getRepository().getFile( fileUrl );
if ( !getAclHelper().canAccess( getRepository().getFile( dsPath ), EnumSet.of( RepositoryFilePermission.READ ) ) ) {
repositoryFile = null;
}
}
public boolean exists() throws FileSystemException {
initFile();
return repositoryFile != null;
}
public boolean isHidden() throws FileSystemException {
// not needed for our usage
return false;
}
public boolean isReadable() throws FileSystemException {
// not needed for our usage
return exists();
}
public boolean isWriteable() throws FileSystemException {
// not needed for our usage
return false;
}
public FileType getType() throws FileSystemException {
return ( ( repositoryFile != null ) && !repositoryFile.isFolder() ) ? FileType.FILE : FileType.FOLDER;
}
public FileObject getParent() throws FileSystemException {
// not needed for our usage
return null;
}
@Override public String getPublicURIString() {
throw new UnsupportedOperationException();
}
public FileSystem getFileSystem() {
// not needed for our usage
return null;
}
public FileObject[] getChildren() throws FileSystemException {
List<FileObject> fileList = new ArrayList<FileObject>();
if ( exists() ) {
for ( RepositoryFile child : getRepository().getChildren( repositoryFile.getId() ) ) {
SolutionRepositoryVfsFileObject fileInfo = new SolutionRepositoryVfsFileObject( child.getPath() );
fileList.add( fileInfo );
}
}
return fileList.toArray( new FileObject[0] );
}
public FileObject getChild( final String arg0 ) throws FileSystemException {
// not needed for our usage
return null;
}
public FileObject resolveFile( final String arg0, final NameScope arg1 ) throws FileSystemException {
// not needed for our usage
return null;
}
@Override public boolean setExecutable( boolean executable, boolean ownerOnly ) throws FileSystemException {
throw new UnsupportedOperationException();
}
@Override public boolean setReadable( boolean readable, boolean ownerOnly ) throws FileSystemException {
throw new UnsupportedOperationException();
}
@Override public boolean setWritable( boolean writable, boolean ownerOnly ) throws FileSystemException {
throw new UnsupportedOperationException();
}
public FileObject resolveFile( final String arg0 ) throws FileSystemException {
// not needed for our usage
return null;
}
public FileObject[] findFiles( final FileSelector arg0 ) throws FileSystemException {
// not needed for our usage
return null;
}
public void findFiles( final FileSelector arg0, final boolean arg1, final List arg2 ) throws FileSystemException {
// not needed for our usage
}
public boolean delete() throws FileSystemException {
// not needed for our usage
return false;
}
public int delete( final FileSelector arg0 ) throws FileSystemException {
// not needed for our usage
return 0;
}
@Override public int deleteAll() throws FileSystemException {
throw new UnsupportedOperationException();
}
public void createFolder() throws FileSystemException {
// not needed for our usage
}
public void createFile() throws FileSystemException {
// not needed for our usage
}
public void copyFrom( final FileObject arg0, final FileSelector arg1 ) throws FileSystemException {
// not needed for our usage
}
public void moveTo( final FileObject arg0 ) throws FileSystemException {
// not needed for our usage
}
public boolean canRenameTo( final FileObject arg0 ) {
// not needed for our usage
return false;
}
public FileContent getContent() throws FileSystemException {
content = new SolutionRepositoryVfsFileContent( this );
return content;
}
public void close() throws FileSystemException {
if ( content != null ) {
content.close();
content = null;
}
}
public void refresh() throws FileSystemException {
// not needed for our usage
}
public boolean isAttached() {
// not needed for our usage
return false;
}
public boolean isContentOpen() {
return ( content != null ) && content.isOpen();
}
@Override public boolean isExecutable() throws FileSystemException {
throw new UnsupportedOperationException();
}
@Override public boolean isFile() throws FileSystemException {
return getType().equals( FileType.FILE );
}
@Override public boolean isFolder() throws FileSystemException {
throw new UnsupportedOperationException();
}
public FileOperations getFileOperations() throws FileSystemException {
// not needed for our usage
return null;
}
public InputStream getInputStream() throws UnifiedRepositoryException, FileSystemException {
InputStream inputStream = null;
if ( exists() ) {
String extension = FilenameUtils.getExtension( repositoryFile.getPath() );
// Try to get the converter for the extension. If there is not converter available then we will
//assume simple type and will get the data that way
if ( getConverterHandler() != null ) {
Converter converter = getConverterHandler().getConverter( extension );
if ( converter != null ) {
inputStream = converter.convert( repositoryFile.getId() );
}
}
if ( inputStream == null ) {
inputStream = getRepository().getDataForRead( repositoryFile.getId(), SimpleRepositoryFileData.class ).getStream();
}
}
return inputStream;
}
protected synchronized IAclNodeHelper getAclHelper() {
if ( testAclHelper != null ) {
return testAclHelper;
}
if ( aclHelper == null ) {
aclHelper = new JcrAclNodeHelper( getRepository() );
}
return aclHelper;
}
/**
* We do not control the lifecycle (creation) of these class instances. Therefore, for testing purposes when we need
* to override the IAclNodeHelper, this is the method to call.
*
* @param helper
*/
@VisibleForTesting
public static void setTestAclHelper( IAclNodeHelper helper ) {
testAclHelper = helper;
}
@Override public int compareTo( FileObject file ) {
return file == null ? 1 : this.getName().getURI().compareTo( file.getName().getURI() );
}
@Override public Iterator<FileObject> iterator() {
throw new UnsupportedOperationException();
}
}