Java tutorial
/* * 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. * * 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.datamodel.backend.server; import java.net.URISyntaxException; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import javax.enterprise.event.Event; import javax.inject.Inject; import javax.inject.Named; import org.apache.commons.lang3.exception.ExceptionUtils; import org.guvnor.common.services.builder.ResourceChangeIncrementalBuilder; import org.guvnor.common.services.project.builder.events.InvalidateDMOProjectCacheEvent; import org.guvnor.common.services.project.builder.model.BuildResults; import org.guvnor.common.services.project.builder.service.BuildService; import org.guvnor.test.WeldJUnitRunner; import org.junit.Test; import org.junit.runner.RunWith; import org.kie.workbench.common.services.datamodel.backend.server.service.DataModelService; import org.kie.workbench.common.services.shared.project.KieProject; 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.io.IOService; import org.uberfire.rpc.SessionInfo; import static org.junit.Assert.*; @RunWith(WeldJUnitRunner.class) public class ProjectDataModelConcurrencyTest { private static final Logger logger = LoggerFactory.getLogger(ProjectDataModelConcurrencyTest.class); @Inject private Paths paths; @Inject private BuildResultsObserver buildResultsObserver; @Inject private BuildService buildService; @Inject private KieProjectService projectService; @Inject private DataModelService dataModelService; @Inject private ResourceChangeIncrementalBuilder buildChangeListener; @Inject private SessionInfo sessionInfo; @Inject @Named("ioStrategy") private IOService ioService; @Inject private Event<InvalidateDMOProjectCacheEvent> invalidateDMOProjectCacheEvent; @Test public void testConcurrentResourceUpdates() throws URISyntaxException { final URL pomUrl = this.getClass().getResource("/DataModelBackendTest1/pom.xml"); final org.uberfire.java.nio.file.Path nioPomPath = ioService.get(pomUrl.toURI()); final Path pomPath = paths.convert(nioPomPath); final URL resourceUrl = this.getClass().getResource("/DataModelBackendTest1/src/main/resources/empty.rdrl"); final org.uberfire.java.nio.file.Path nioResourcePath = ioService.get(resourceUrl.toURI()); final Path resourcePath = paths.convert(nioResourcePath); //Force full build before attempting incremental changes final KieProject project = projectService.resolveProject(resourcePath); final BuildResults buildResults = buildService.build(project); assertNotNull(buildResults); assertEquals(0, buildResults.getErrorMessages().size()); assertEquals(1, buildResults.getInformationMessages().size()); //Perform incremental build final int THREADS = 200; final Result result = new Result(); ExecutorService es = Executors.newCachedThreadPool(); for (int i = 0; i < THREADS; i++) { final int operation = (i % 3); switch (operation) { case 0: es.execute(new Runnable() { @Override public void run() { try { logger.debug("[Thread: " + Thread.currentThread().getName() + "] Request to update POM received"); invalidateCaches(project, pomPath); buildChangeListener.updateResource(pomPath); logger.debug("[Thread: " + Thread.currentThread().getName() + "] POM update completed"); } catch (Throwable e) { result.setFailed(true); result.setMessage(e.getMessage()); ExceptionUtils.printRootCauseStackTrace(e); } } }); break; case 1: es.execute(new Runnable() { @Override public void run() { try { logger.debug("[Thread: " + Thread.currentThread().getName() + "] Request to update Resource received"); invalidateCaches(project, resourcePath); buildChangeListener.addResource(resourcePath); logger.debug( "[Thread: " + Thread.currentThread().getName() + "] Resource update completed"); } catch (Throwable e) { result.setFailed(true); result.setMessage(e.getMessage()); ExceptionUtils.printRootCauseStackTrace(e); } } }); break; case 2: es.execute(new Runnable() { @Override public void run() { try { logger.debug("[Thread: " + Thread.currentThread().getName() + "] Request for DataModel received"); dataModelService.getDataModel(resourcePath); logger.debug("[Thread: " + Thread.currentThread().getName() + "] DataModel request completed"); } catch (Throwable e) { result.setFailed(true); result.setMessage(e.getMessage()); ExceptionUtils.printRootCauseStackTrace(e); } } }); } } es.shutdown(); try { es.awaitTermination(5, TimeUnit.MINUTES); } catch (InterruptedException e) { } if (result.isFailed()) { fail(result.getMessage()); } } private void invalidateCaches(final KieProject project, final Path resourcePath) { invalidateDMOProjectCacheEvent.fire(new InvalidateDMOProjectCacheEvent(sessionInfo, project, resourcePath)); } private static class Result { private boolean failed = false; private String message = ""; public synchronized boolean isFailed() { return failed; } public synchronized void setFailed(boolean failed) { this.failed = failed; } public synchronized String getMessage() { return message; } public synchronized void setMessage(String message) { this.message = message; } } }