/* * Copyright 2012 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.workbench.screens.dtablexls.backend.server; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Event; import javax.inject.Inject; import javax.inject.Named; import org.apache.commons.io.IOUtils; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.drools.decisiontable.InputType; import org.drools.decisiontable.SpreadsheetCompiler; import org.drools.template.parser.DecisionTableParseException; import org.drools.workbench.models.guided.dtable.shared.conversion.ConversionResult; import org.drools.workbench.screens.dtablexls.service.DecisionTableXLSContent; import org.drools.workbench.screens.dtablexls.service.DecisionTableXLSConversionService; import org.drools.workbench.screens.dtablexls.service.DecisionTableXLSService; import org.guvnor.common.services.backend.config.SafeSessionInfo; import org.guvnor.common.services.backend.exceptions.ExceptionUtilities; import org.guvnor.common.services.backend.util.CommentedOptionFactory; import org.guvnor.common.services.backend.validation.GenericValidator; import org.guvnor.common.services.shared.metadata.model.Overview; import org.guvnor.common.services.shared.validation.model.ValidationMessage; import org.jboss.errai.bus.server.annotations.Service; import org.jboss.errai.security.shared.service.AuthenticationService; import org.kie.workbench.common.services.backend.service.KieService; import org.kie.workbench.common.services.shared.source.SourceGenerationFailedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.uberfire.backend.server.util.Paths; import org.uberfire.backend.vfs.Path; import org.uberfire.ext.editor.commons.service.CopyService; import org.uberfire.ext.editor.commons.service.DeleteService; import org.uberfire.ext.editor.commons.service.RenameService; import org.uberfire.io.IOService; import org.uberfire.java.nio.file.StandardOpenOption; import org.uberfire.rpc.SessionInfo; import org.uberfire.rpc.impl.SessionInfoImpl; import org.uberfire.workbench.events.ResourceOpenedEvent; @Service @ApplicationScoped // Implementation needs to implement both interfaces even though one extends the other // otherwise the implementation discovery mechanism for the @Service annotation fails. public class DecisionTableXLSServiceImpl extends KieService<DecisionTableXLSContent> implements DecisionTableXLSService, ExtendedDecisionTableXLSService { private static final Logger log = LoggerFactory.getLogger( DecisionTableXLSServiceImpl.class ); private IOService ioService; private CopyService copyService; private DeleteService deleteService; private RenameService renameService; private Event<ResourceOpenedEvent> resourceOpenedEvent; private DecisionTableXLSConversionService conversionService; private GenericValidator genericValidator; private CommentedOptionFactory commentedOptionFactory; private AuthenticationService authenticationService; public DecisionTableXLSServiceImpl() { } @Inject public DecisionTableXLSServiceImpl( @Named("ioStrategy") final IOService ioService, final CopyService copyService, final DeleteService deleteService, final RenameService renameService, final Event<ResourceOpenedEvent> resourceOpenedEvent, final DecisionTableXLSConversionService conversionService, final GenericValidator genericValidator, final CommentedOptionFactory commentedOptionFactory, final AuthenticationService authenticationService ) { this.ioService = ioService; this.copyService = copyService; this.deleteService = deleteService; this.renameService = renameService; this.resourceOpenedEvent = resourceOpenedEvent; this.conversionService = conversionService; this.genericValidator = genericValidator; this.commentedOptionFactory = commentedOptionFactory; this.authenticationService = authenticationService; } @Override public DecisionTableXLSContent loadContent( final Path path ) { return super.loadContent( path ); } @Override protected DecisionTableXLSContent constructContent( Path path, Overview overview ) { final DecisionTableXLSContent content = new DecisionTableXLSContent(); content.setOverview( overview ); return content; } @Override public InputStream load( final Path path, final String sessionId ) { try { final InputStream inputStream = ioService.newInputStream( Paths.convert( path ), StandardOpenOption.READ ); //Signal opening to interested parties resourceOpenedEvent.fire( new ResourceOpenedEvent( path, getSessionInfo( sessionId ) ) ); return inputStream; } catch ( Exception e ) { throw ExceptionUtilities.handleException( e ); } } @Override public Path create( final Path resource, final InputStream content, final String sessionId, final String comment ) { return writeToFile( resource, content, sessionId, comment, true ); } @Override public Path save( final Path resource, final InputStream content, final String sessionId, final String comment ) { return writeToFile( resource, content, sessionId, comment, false ); } private Path writeToFile( final Path resource, final InputStream content, final String sessionId, final String comment, boolean create ) { final SessionInfo sessionInfo = getSessionInfo( sessionId ); String userAction = "UPDATING"; if ( create ) { userAction = "CREATING"; } log.info( "USER:" + sessionInfo.getIdentity().getIdentifier() + " " + userAction + " asset [" + resource.getFileName() + "]" ); FileInputStream tempFIS = null; FileOutputStream tempFOS = null; OutputStream outputStream = null; try { File tempFile = File.createTempFile( "testxls", null ); tempFOS = new FileOutputStream( tempFile ); IOUtils.copy( content, tempFOS ); tempFOS.flush(); //Validate the xls validate( tempFile ); final org.uberfire.java.nio.file.Path nioPath = Paths.convert( resource ); if ( create ) { ioService.createFile( nioPath ); } outputStream = ioService.newOutputStream( nioPath, commentedOptionFactory.makeCommentedOption( comment, sessionInfo.getIdentity(), sessionInfo ) ); //InputStream 'content' has been fully read to write to the temp file; so we need to use a new InputStream //An alternative is to check for content.markSupported() and reset() however since we have a temporary //file we may as well use it! tempFIS = new FileInputStream( tempFile ); IOUtils.copy( tempFIS, outputStream ); outputStream.flush(); //Read Path to ensure attributes have been set final Path newPath = Paths.convert( nioPath ); return newPath; } catch ( Exception e ) { throw ExceptionUtilities.handleException( e ); } finally { try { content.close(); } catch ( IOException e ) { throw ExceptionUtilities.handleException( e ); } if ( tempFIS != null ) { try { tempFIS.close(); } catch ( IOException e ) { throw ExceptionUtilities.handleException( e ); } } if ( tempFOS != null ) { try { tempFOS.close(); } catch ( IOException e ) { throw ExceptionUtilities.handleException( e ); } } if ( outputStream != null ) { try { outputStream.close(); } catch ( IOException e ) { throw ExceptionUtilities.handleException( e ); } } } } void validate( final File tempFile ) { Workbook workbook = null; try { workbook = WorkbookFactory.create( tempFile ); } catch ( InvalidFormatException e ) { throw new DecisionTableParseException( "DecisionTableParseException: An error occurred opening the workbook. It is possible that the encoding of the document did not match the encoding of the reader.", e ); } catch ( IOException e ) { throw new DecisionTableParseException( "DecisionTableParseException: Failed to open Excel stream, " + "please check that the content is xls97 format.", e ); } catch ( Throwable e ) { throw new DecisionTableParseException( "DecisionTableParseException: " + e.getMessage(), e ); } finally { if ( workbook != null ) { try { workbook.close(); } catch ( IOException e ) { throw ExceptionUtilities.handleException( e ); } } } } @Override public String getSource( final Path path ) { InputStream inputStream = null; try { final SpreadsheetCompiler compiler = new SpreadsheetCompiler(); inputStream = ioService.newInputStream( Paths.convert( path ), StandardOpenOption.READ ); final String drl = compiler.compile( inputStream, InputType.XLS ); return drl; } catch ( Exception e ) { throw new SourceGenerationFailedException( e.getMessage() ); } finally { if ( inputStream != null ) { try { inputStream.close(); } catch ( IOException ioe ) { throw ExceptionUtilities.handleException( ioe ); } } } } @Override public void delete( final Path path, final String comment ) { try { deleteService.delete( path, comment ); } catch ( Exception e ) { throw ExceptionUtilities.handleException( e ); } } @Override public Path rename( final Path path, final String newName, final String comment ) { try { return renameService.rename( path, newName, comment ); } catch ( Exception e ) { throw ExceptionUtilities.handleException( e ); } } @Override public Path copy( final Path path, final String newName, final String comment ) { try { return copyService.copy( path, newName, comment ); } catch ( Exception e ) { throw ExceptionUtilities.handleException( e ); } } @Override public Path copy( final Path path, final String newName, final Path targetDirectory, final String comment ) { try { return copyService.copy( path, newName, targetDirectory, comment ); } catch ( Exception e ) { throw ExceptionUtilities.handleException( e ); } } @Override public ConversionResult convert( final Path path ) { try { return conversionService.convert( path ); } catch ( Exception e ) { throw ExceptionUtilities.handleException( e ); } } @Override public List<ValidationMessage> validate( final Path path, final Path resource ) { try { return genericValidator.validate( path ); } catch ( Exception e ) { throw ExceptionUtilities.handleException( e ); } } private SessionInfo getSessionInfo( final String sessionId ) { return new SafeSessionInfo( new SessionInfoImpl( sessionId, authenticationService.getUser() ) ); } }