org.kie.workbench.common.services.datamodel.backend.server.ProjectDataModelConcurrencyTest.java Source code

Java tutorial

Introduction

Here is the source code for org.kie.workbench.common.services.datamodel.backend.server.ProjectDataModelConcurrencyTest.java

Source

/*
 * 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;
        }
    }

}