/*
* Copyright 2015 - 2017 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.server.services.impl;
import org.drools.core.command.impl.ExecutableCommand;
import org.drools.core.command.runtime.BatchExecutionCommandImpl;
import org.kie.api.command.Command;
import org.kie.api.runtime.CommandExecutor;
import org.kie.api.runtime.ExecutionResults;
import org.kie.server.api.commands.CallContainerCommand;
import org.kie.server.api.commands.CommandScript;
import org.kie.server.api.commands.CreateContainerCommand;
import org.kie.server.api.commands.DisposeContainerCommand;
import org.kie.server.api.commands.GetContainerInfoCommand;
import org.kie.server.api.commands.GetReleaseIdCommand;
import org.kie.server.api.commands.GetScannerInfoCommand;
import org.kie.server.api.commands.GetServerInfoCommand;
import org.kie.server.api.commands.GetServerStateCommand;
import org.kie.server.api.commands.ListContainersCommand;
import org.kie.server.api.commands.UpdateReleaseIdCommand;
import org.kie.server.api.commands.UpdateScannerCommand;
import org.kie.server.api.marshalling.Marshaller;
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.api.model.KieServerCommand;
import org.kie.server.api.model.ServiceResponse;
import org.kie.server.api.model.ServiceResponsesList;
import org.kie.server.services.api.KieContainerCommandService;
import org.kie.server.services.api.KieServerRegistry;
import org.kie.server.services.impl.locator.ContainerLocatorProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class KieContainerCommandServiceImpl implements KieContainerCommandService<ExecutionResults> {
protected static final Pattern LOOKUP = Pattern.compile("[\"']?lookup[\"']?\\s*[:=]\\s*[\"']([^\"']+)[\"']");
private static final Logger logger = LoggerFactory.getLogger(KieContainerCommandServiceImpl.class);
protected KieServerImpl kieServer;
protected final KieServerRegistry context;
public KieContainerCommandServiceImpl(KieServerImpl kieServer, KieServerRegistry context) {
this.kieServer = kieServer;
this.context = context;
}
public ServiceResponse<ExecutionResults> callContainer(String containerId, String payload, MarshallingFormat marshallingFormat, String classType) {
return callContainer(containerId, payload, marshallingFormat, classType, false);
}
protected ServiceResponse<ExecutionResults> callContainer(String containerId, String payload, MarshallingFormat marshallingFormat, String classType, boolean marshallResponse) {
if( payload == null ) {
return new ServiceResponse<ExecutionResults>(ServiceResponse.ResponseType.FAILURE, "Error calling container " + containerId + ". Empty payload. ");
}
try {
KieContainerInstanceImpl kci = (KieContainerInstanceImpl) context.getContainer( containerId, ContainerLocatorProvider.get().getLocator() );
// the following code is subject to a concurrent call to dispose(), but the cost of synchronizing it
// would likely not be worth it. At this point a decision was made to fail the execution if a concurrent
// call do dispose() is executed.
if (kci != null && kci.getKieContainer() != null) {
String sessionId = null;
// this is a weak way of finding the lookup, but it is the same used in kie-camel. Will keep it for now.
Matcher m = LOOKUP.matcher(payload);
if (m.find()) {
sessionId = m.group(1);
}
// find the session
CommandExecutor ks = null;
if( sessionId != null ) {
ks = context.getKieSessionLookupManager().lookup(sessionId, kci, context);
} else {
// if no session ID is defined, then the default is a stateful session
ks = kci.getKieContainer().getKieSession();
}
if (ks != null) {
Class<? extends Command> type = BatchExecutionCommandImpl.class;
if (classType != null && !classType.isEmpty()) {
type = (Class<? extends Command>) kci.getKieContainer().getClassLoader().loadClass(classType);
}
Command<?> cmd = kci.getMarshaller( marshallingFormat ).unmarshall(payload, type);
if (cmd == null) {
return new ServiceResponse<ExecutionResults>(ServiceResponse.ResponseType.FAILURE, "Body of in message not of the expected type '" + Command.class.getName() + "'");
}
if (!(cmd instanceof BatchExecutionCommandImpl)) {
cmd = new BatchExecutionCommandImpl(Arrays.asList(new ExecutableCommand<?>[]{(ExecutableCommand<?>) cmd} ));
}
ExecutionResults results = ks.execute((BatchExecutionCommandImpl) cmd);
if (marshallResponse) {
Marshaller marshaller = kci.getMarshaller(marshallingFormat);
String result = marshaller.marshall(results);
return new ServiceResponse(ServiceResponse.ResponseType.SUCCESS, "Container " + containerId + " successfully called.", result);
} else {
return new ServiceResponse<ExecutionResults>(ServiceResponse.ResponseType.SUCCESS, "Container " + containerId + " successfully called.", results);
}
} else {
return new ServiceResponse<ExecutionResults>(ServiceResponse.ResponseType.FAILURE, "Session '" + sessionId + "' not found on container '" + containerId + "'.");
}
} else {
return new ServiceResponse<ExecutionResults>(ServiceResponse.ResponseType.FAILURE, "Container " + containerId + " is not instantiated.");
}
} catch (Exception e) {
logger.error("Error calling container '" + containerId + "'", e);
return new ServiceResponse<ExecutionResults>(ServiceResponse.ResponseType.FAILURE, "Error calling container " + containerId + ": " +
e.getClass().getName() + ": " + e.getMessage());
}
}
@Override
public ServiceResponsesList executeScript(CommandScript commands, MarshallingFormat marshallingFormat, String classType) {
List<ServiceResponse<? extends Object>> responses = new ArrayList<ServiceResponse<? extends Object>>();
if( commands != null ) {
for (KieServerCommand command : commands.getCommands()) {
if (command instanceof CreateContainerCommand) {
responses.add(this.kieServer.createContainer(((CreateContainerCommand) command).getContainer().getContainerId(), ((CreateContainerCommand) command).getContainer()));
} else if (command instanceof GetServerInfoCommand) {
responses.add(this.kieServer.getInfo());
} else if (command instanceof ListContainersCommand) {
responses.add(this.kieServer.listContainers(((ListContainersCommand)command).getKieContainerResourceFilter()));
} else if (command instanceof CallContainerCommand) {
ServiceResponse response = callContainer(((CallContainerCommand) command).getContainerId(), ((CallContainerCommand) command).getPayload(), marshallingFormat, classType, true);
responses.add(response);
} else if (command instanceof DisposeContainerCommand) {
responses.add(this.kieServer.disposeContainer(((DisposeContainerCommand) command).getContainerId()));
} else if (command instanceof GetContainerInfoCommand) {
responses.add(this.kieServer.getContainerInfo(((GetContainerInfoCommand) command).getContainerId()));
} else if (command instanceof GetScannerInfoCommand) {
responses.add(this.kieServer.getScannerInfo(((GetScannerInfoCommand) command).getContainerId()));
} else if (command instanceof UpdateScannerCommand) {
responses.add(this.kieServer.updateScanner(((UpdateScannerCommand) command).getContainerId(), ((UpdateScannerCommand) command).getScanner()));
} else if (command instanceof GetReleaseIdCommand) {
responses.add(this.kieServer.getContainerReleaseId(((GetReleaseIdCommand) command).getContainerId()));
} else if (command instanceof UpdateReleaseIdCommand) {
responses.add(this.kieServer.updateContainerReleaseId(((UpdateReleaseIdCommand) command).getContainerId(), ((UpdateReleaseIdCommand) command).getReleaseId()));
} else if (command instanceof GetServerStateCommand) {
responses.add(this.kieServer.getServerState());
}
}
}
return new ServiceResponsesList(responses);
}
}