/*
* Copyright 2016 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.kie.workbench.common.screens.datasource.management.backend.service;
import org.guvnor.common.services.backend.exceptions.ExceptionUtilities;
import org.guvnor.common.services.backend.util.CommentedOptionFactory;
import org.guvnor.common.services.project.model.Project;
import org.kie.workbench.common.screens.datasource.management.backend.core.DataSourceRuntimeManager;
import org.kie.workbench.common.screens.datasource.management.backend.core.DeploymentOptions;
import org.kie.workbench.common.screens.datasource.management.backend.core.UnDeploymentOptions;
import org.kie.workbench.common.screens.datasource.management.model.Def;
import org.kie.workbench.common.screens.datasource.management.model.DefEditorContent;
import org.kie.workbench.common.screens.datasource.management.model.DeploymentInfo;
import org.kie.workbench.common.screens.datasource.management.util.MavenArtifactResolver;
import org.kie.workbench.common.screens.datasource.management.util.UUIDGenerator;
import org.kie.workbench.common.services.shared.project.KieProjectService;
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.PathNamingService;
import org.uberfire.io.IOService;
import org.uberfire.java.nio.file.FileAlreadyExistsException;
import static org.uberfire.commons.validation.PortablePreconditions.*;
public abstract class AbstractDefEditorService<C extends DefEditorContent<D>,D extends Def, I extends DeploymentInfo> {
private static final Logger logger = LoggerFactory.getLogger( AbstractDefEditorService.class );
protected DataSourceRuntimeManager runtimeManager;
protected DataSourceServicesHelper serviceHelper;
protected IOService ioService;
protected KieProjectService projectService;
protected CommentedOptionFactory optionsFactory;
protected PathNamingService pathNamingService;
protected MavenArtifactResolver artifactResolver;
public AbstractDefEditorService() {
}
public AbstractDefEditorService( DataSourceRuntimeManager runtimeManager,
DataSourceServicesHelper serviceHelper,
IOService ioService,
KieProjectService projectService,
CommentedOptionFactory optionsFactory,
PathNamingService pathNamingService,
MavenArtifactResolver artifactResolver ) {
this.runtimeManager = runtimeManager;
this.serviceHelper = serviceHelper;
this.ioService = ioService;
this.projectService = projectService;
this.optionsFactory = optionsFactory;
this.pathNamingService = pathNamingService;
this.artifactResolver = artifactResolver;
}
protected abstract C newContent();
protected abstract String serializeDef( D def );
protected abstract D deserializeDef( String source );
protected abstract I readDeploymentInfo( String uuid ) throws Exception;
protected abstract void deploy( D def, DeploymentOptions options ) throws Exception;
protected abstract void unDeploy( I deploymentInfo, UnDeploymentOptions options ) throws Exception;
protected abstract void fireCreateEvent( D def, Project project );
protected abstract void fireCreateEvent( D def );
protected abstract void fireUpdateEvent( D def, Project project, D originalDef );
protected abstract void fireDeleteEvent( D def, Project project );
protected abstract String buildFileName( D def );
public C loadContent( final Path path ) {
checkNotNull( "path", path );
C editorContent = newContent();
String content = ioService.readAllString( Paths.convert( path ) );
D def = deserializeDef( content );
editorContent.setDef( def );
editorContent.setProject( projectService.resolveProject( path ) );
return editorContent;
}
public Path save( final Path path,
final C editorContent,
final String comment ) {
checkNotNull( "path", path );
checkNotNull( "content", editorContent );
Path newPath = path;
boolean onBatch = false;
try {
final D originalDef = deserializeDef( ioService.readAllString( Paths.convert( path ) ) );
final String content = serializeDef( editorContent.getDef() );
I deploymentInfo = readDeploymentInfo( editorContent.getDef().getUuid() );
if ( deploymentInfo != null ) {
unDeploy( deploymentInfo, UnDeploymentOptions.forcedUnDeployment() );
}
deploy( editorContent.getDef(), DeploymentOptions.create() );
final org.uberfire.java.nio.file.Path _path = Paths.convert( path );
ioService.startBatch( _path.getFileSystem() );
onBatch = true;
serviceHelper.getDefRegistry().invalidateCache( path );
ioService.write( _path, content, optionsFactory.makeCommentedOption( comment ) );
if ( originalDef.getName() != null &&
!originalDef.getName().equals( editorContent.getDef().getName() ) ) {
final org.uberfire.java.nio.file.Path _target =
Paths.convert( pathNamingService.buildTargetPath( path, editorContent.getDef().getName() ) );
ioService.move( _path, _target, optionsFactory.makeCommentedOption( comment ) );
newPath = Paths.convert( _target );
}
serviceHelper.getDefRegistry().setEntry( newPath, editorContent.getDef() );
fireUpdateEvent( editorContent.getDef(), editorContent.getProject(), originalDef );
} catch ( Exception e ) {
throw ExceptionUtilities.handleException( e );
} finally {
if ( onBatch ) {
ioService.endBatch();
}
}
return newPath;
}
public Path create( final D def, final Project project ) {
checkNotNull( "def", def );
checkNotNull( "project", project );
Path context = serviceHelper.getProjectDataSourcesContext( project );
Path newPath = create( def , context );
fireCreateEvent( def, project );
return newPath;
}
public Path createGlobal( final D def ) {
checkNotNull( "def", def );
Path context = serviceHelper.getGlobalDataSourcesContext();
Path newPath = create( def, context );
fireCreateEvent( def );
return newPath;
}
protected Path create( final D def, final Path context ) {
checkNotNull( "def", def );
checkNotNull( "context", context );
if ( def.getUuid() == null ) {
def.setUuid( UUIDGenerator.generateUUID() );
}
String fileName = buildFileName( def );
String content = serializeDef( def );
final org.uberfire.java.nio.file.Path nioPath = Paths.convert( context ).resolve( fileName );
final Path newPath = Paths.convert( nioPath );
if ( ioService.exists( nioPath ) ) {
throw new FileAlreadyExistsException( nioPath.toString() );
}
try {
ioService.startBatch( nioPath.getFileSystem( ) );
//create the file.
ioService.write( nioPath, content, optionsFactory.makeCommentedOption( "" ) );
serviceHelper.getDefRegistry( ).setEntry( newPath, def );
} catch ( Exception e ) {
logger.error( "It was not possible to create: " + def.getName(), e );
ioService.endBatch();
throw ExceptionUtilities.handleException( e );
}
try {
//proceed with the deployment
deploy( def, DeploymentOptions.create() );
} catch ( Exception e1 ) {
logger.error( "It was not possible to create: " + def.getName(), e1 );
serviceHelper.getDefRegistry().invalidateCache( newPath );
//the file was created, but the deployment failed.
try {
ioService.delete( nioPath );
} catch ( Exception e2 ) {
logger.warn( "Removal of orphan definition file failed: " + newPath, e2 );
}
throw ExceptionUtilities.handleException( e1 );
} finally {
ioService.endBatch();
}
return newPath;
}
public void delete( final Path path, final String comment ) {
checkNotNull( "path", path );
final org.uberfire.java.nio.file.Path nioPath = Paths.convert( path );
if ( ioService.exists( nioPath ) ) {
String content = ioService.readAllString( Paths.convert( path ) );
D def = deserializeDef( content );
Project project = projectService.resolveProject( path );
try {
I deploymentInfo = readDeploymentInfo( def.getUuid() );
if ( deploymentInfo != null ) {
unDeploy( deploymentInfo, UnDeploymentOptions.forcedUnDeployment() );
}
serviceHelper.getDefRegistry().invalidateCache( path );
ioService.delete( Paths.convert( path ), optionsFactory.makeCommentedOption( comment ) );
fireDeleteEvent( def, project );
} catch ( Exception e ) {
throw ExceptionUtilities.handleException( e );
}
}
}
}