/* * 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.services.backend.validation.asset; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.inject.Named; import com.google.common.base.Charsets; import org.guvnor.common.services.project.builder.model.IncrementalBuildResults; import org.guvnor.common.services.project.model.Project; import org.guvnor.common.services.shared.message.Level; import org.guvnor.common.services.shared.validation.model.ValidationMessage; import org.kie.workbench.common.services.backend.builder.service.BuildInfo; import org.kie.workbench.common.services.backend.builder.service.BuildInfoImpl; import org.kie.workbench.common.services.backend.builder.service.BuildInfoService; import org.kie.workbench.common.services.backend.builder.core.Builder; import org.kie.workbench.common.services.backend.builder.core.LRUBuilderCache; import org.kie.workbench.common.services.shared.project.KieProjectService; import org.uberfire.backend.server.util.Paths; import org.uberfire.backend.vfs.Path; import org.uberfire.io.IOService; @ApplicationScoped public class ValidatorBuildService { private final static String ERROR_CLASS_NOT_FOUND = "Definition of class \"{0}\" was not found. Consequentially validation cannot be performed.\nPlease check the necessary external dependencies for this project are configured correctly."; private IOService ioService; private LRUBuilderCache builderCache; private KieProjectService projectService; private BuildInfoService buildInfoService; public ValidatorBuildService() { //CDI proxies } @Inject public ValidatorBuildService( final @Named("ioStrategy") IOService ioService, final LRUBuilderCache builderCache, final KieProjectService projectService, final BuildInfoService buildInfoService ) { this.ioService = ioService; this.builderCache = builderCache; this.projectService = projectService; this.buildInfoService = buildInfoService; } public List<ValidationMessage> validate( final Path resourcePath, final String content ) { InputStream inputStream = null; try { inputStream = new ByteArrayInputStream( content.getBytes( Charsets.UTF_8 ) ); final List<ValidationMessage> results = doValidation( resourcePath, inputStream ); return results; } catch ( NoProjectException e ) { return new ArrayList<>(); } catch ( NoClassDefFoundError e ) { return error( MessageFormat.format( ERROR_CLASS_NOT_FOUND, e.getLocalizedMessage() ) ); } catch ( Throwable e ) { return error( e.getLocalizedMessage() ); } finally { if ( inputStream != null ) { try { inputStream.close(); } catch ( IOException e ) { } } } } public List<ValidationMessage> validate( final Path resourcePath ) { InputStream inputStream = null; try { inputStream = ioService.newInputStream( Paths.convert( resourcePath ) ); final List<ValidationMessage> results = doValidation( resourcePath, inputStream ); return results; } catch ( NoProjectException e ) { return new ArrayList<>(); } catch ( NoClassDefFoundError e ) { return error( MessageFormat.format( ERROR_CLASS_NOT_FOUND, e.getLocalizedMessage() ) ); } catch ( Throwable e ) { return error( e.getLocalizedMessage() ); } finally { if ( inputStream != null ) { try { inputStream.close(); } catch ( IOException e ) { } } } } private List<ValidationMessage> doValidation( final Path resourcePath, final InputStream inputStream ) throws NoProjectException { final ValidatorResultBuilder resultBuilder = new ValidatorResultBuilder(); final Project project = project( resourcePath ); final org.uberfire.java.nio.file.Path nioResourcePath = Paths.convert( resourcePath ); //Incremental Build does not support Java classes if ( isIncrementalBuildPossible( resourcePath ) ) { //Build the Builder from the cache so it's "built" state can be preserved for re-use BuildInfo buildInfo = buildInfoService.getBuildInfo( project ); final Builder clone = ( ( BuildInfoImpl ) buildInfo ).getBuilder().clone(); //First delete resource otherwise if the resource already had errors following builder.build() //the incremental compilation will not report any additional errors and the resource will be //considered valid. clone.deleteResource( nioResourcePath ); final IncrementalBuildResults incrementalBuildResults = clone.updateResource( nioResourcePath, inputStream ); resultBuilder.add( incrementalBuildResults.getAddedMessages() ); } else { Builder builder = builderCache.assertBuilder( project( resourcePath ) ); final Builder clone = builder.clone(); resultBuilder.add( clone.build( nioResourcePath, inputStream ).getMessages() ); } return resultBuilder.results(); } private boolean isIncrementalBuildPossible( final Path resourcePath ) throws NoProjectException { final boolean isResource = getDestinationPath( resourcePath ).startsWith( "src/main/resources/" ); return isResource; } private String getDestinationPath( final Path path ) throws NoProjectException { final int rootPathLength = project( path ).getRootPath().toURI().length() + 1; return path.toURI().substring( rootPathLength ); } private Project project( final Path resourcePath ) throws NoProjectException { final Project project = projectService.resolveProject( resourcePath ); if ( project == null ) { throw new NoProjectException(); } return project; } private ArrayList<ValidationMessage> error( final String errorMessage ) { return new ArrayList<ValidationMessage>() {{ add( new ValidationMessage( Level.ERROR, errorMessage ) ); }}; } }