li.strolch.service.api.AbstractService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of agent Show documentation
Show all versions of agent Show documentation
Strolch Agent which is the runtime for Strolch
The newest version!
/*
* Copyright 2013 Robert von Burg
*
* 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 li.strolch.service.api;
import static li.strolch.runtime.StrolchConstants.DEFAULT_REALM;
import static li.strolch.utils.helper.ExceptionHelper.getRootCause;
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.agent.api.StrolchComponent;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.exception.StrolchException;
import li.strolch.exception.StrolchUserMessageException;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.base.PrivilegeException;
import li.strolch.privilege.handler.SystemAction;
import li.strolch.privilege.handler.SystemActionWithResult;
import li.strolch.privilege.model.Certificate;
import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.runtime.StrolchConstants;
import li.strolch.runtime.configuration.RuntimeConfiguration;
import li.strolch.runtime.privilege.PrivilegeHandler;
import li.strolch.runtime.privilege.PrivilegedRunnable;
import li.strolch.runtime.privilege.PrivilegedRunnableWithResult;
import li.strolch.utils.dbc.DBC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Robert von Burg
*/
public abstract class AbstractService implements Service {
protected static final Logger logger = LoggerFactory.getLogger(AbstractService.class);
private ComponentContainer container;
private PrivilegeContext privilegeContext;
/**
* Called by the {@link ServiceHandler} to set the {@link PrivilegeContext} before this service is performed
*
* @param privilegeContext
* the privilegeContext to set
*/
public final void setPrivilegeContext(PrivilegeContext privilegeContext) {
DBC.PRE.assertNull("PrivilegeContext is already set!", this.privilegeContext);
this.privilegeContext = privilegeContext;
}
/**
* Return the {@link PrivilegeContext} to perform further privilege authorization validation
*
* @return the privilegeContext
*/
public final PrivilegeContext getPrivilegeContext() {
return this.privilegeContext;
}
/**
* Returns the {@link Certificate} of the user who is performing this service
*
* @return the certificate
*/
protected final Certificate getCertificate() {
return this.privilegeContext.getCertificate();
}
/**
* Called by the {@link ServiceHandler} to set a reference to the {@link ComponentContainer} to be used during
* service execution
*
* @param container
* the container to set
*/
public final void setContainer(ComponentContainer container) {
this.container = container;
}
/**
* Returns the reference to the {@link ComponentContainer}
*
* @return the container
*/
protected final ComponentContainer getContainer() {
return this.container;
}
/**
* Return the {@link StrolchAgent}
*
* @return the {@link StrolchAgent}
*/
protected final StrolchAgent getAgent() {
return this.container.getAgent();
}
/**
* Returns the reference to the {@link PrivilegeHandler}
*
* @return the privilege handler
*/
public PrivilegeHandler getPrivilegeHandler() throws IllegalArgumentException {
return this.container.getPrivilegeHandler();
}
/**
* Returns the reference to the {@link StrolchComponent} with the given name, if it exists. If it does not exist, an
* {@link IllegalArgumentException} is thrown
*
* @param clazz
* the type of component to return
*
* @return the component with the given name
*
* @throws IllegalArgumentException
* if the component does not exist
*/
protected final V getComponent(Class clazz) {
return this.container.getComponent(clazz);
}
/**
* Returns true if the given component is registered on the {@link ComponentContainer}
*
* @param clazz
* the type of component to check for
*
* @return true if the component is available
*/
public boolean hasComponent(Class> clazz) {
return this.container.hasComponent(clazz);
}
/**
* Returns the Strolch {@link RuntimeConfiguration}
*
* @return the Strolch {@link RuntimeConfiguration}
*/
protected final RuntimeConfiguration getRuntimeConfiguration() {
return this.container.getAgent().getStrolchConfiguration().getRuntimeConfiguration();
}
/**
* Returns the {@link StrolchRealm} with the given name. If the realm does not exist, then a
* {@link StrolchException} is thrown
*
* @param realm
* the name of the {@link StrolchRealm} to return
*
* @return the {@link StrolchRealm} with the given name
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected final StrolchRealm getRealm(String realm) throws StrolchException {
return this.container.getRealm(realm);
}
/**
* Return the Realm for the current certificate
*
* @return the realm
*/
protected StrolchRealm getRealm() {
return this.container.getRealm(getCertificate());
}
/**
* Return the realm name for the current certificate
*
* @return the realm
*/
protected String getRealmName() {
return this.container.getRealm(getCertificate()).getRealm();
}
protected String getArgOrUserRealm(ServiceArgument arg) {
String realm;
if (isNotEmpty(arg.realm))
realm = arg.realm;
else if (isNotEmpty(getCertificate().getRealm()))
realm = getCertificate().getRealm();
else
realm = DEFAULT_REALM;
return realm;
}
/**
* Opens a {@link StrolchTransaction} for the given realm, the action for the TX is this implementation's class
* name. This transaction should be used in a try-with-resource clause so it is properly closed
*
* @param realm
* the name of the realm to return
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openTx(String realm) throws StrolchException {
return getRealm(realm).openTx(getCertificate(), getClass(), false);
}
/**
* Opens a {@link StrolchTransaction} for the given realm, the action for the TX is this implementation's class
* name. This transaction should be used in a try-with-resource clause so it is properly closed
*
* @param realm
* the name of the realm to return
* @param readOnly
* true if this TX is so be read-only
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openTx(String realm, boolean readOnly) throws StrolchException {
return getRealm(realm).openTx(getCertificate(), getClass(), readOnly);
}
/**
* Opens a {@link StrolchTransaction} by evaluating if the given argument has a realm defined, if not, then the
* realm from the user certificate is used. The action for the TX is this implementation's class name. This
* transaction should be used in a try-with-resource clause so it is properly closed
*
* @param arg
* the {@link ServiceArgument}
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openArgOrUserTx(ServiceArgument arg) throws StrolchException {
return openTx(getArgOrUserRealm(arg));
}
/**
* Opens a {@link StrolchTransaction} by evaluating if the given argument has a realm defined, if not, then the
* realm from the user certificate is used. The action for the TX is this implementation's class name. This
* transaction should be used in a try-with-resource clause so it is properly closed
*
* @param arg
* the {@link ServiceArgument}
* @param readOnly
* flag to denote if this TX should be read only
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openArgOrUserTx(ServiceArgument arg, boolean readOnly) throws StrolchException {
return openTx(getArgOrUserRealm(arg), readOnly);
}
/**
* Opens a {@link StrolchTransaction} by evaluating if the given argument has a realm defined, if not, then the
* realm from the user certificate is used. The action for the TX is this implementation's class name. This
* transaction should be used in a try-with-resource clause so it is properly closed
*
* @param arg
* the {@link ServiceArgument}
* @param action
* the action to use for the opened TX
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openArgOrUserTx(ServiceArgument arg, String action) throws StrolchException {
return openTx(getArgOrUserRealm(arg), action);
}
/**
* Opens a {@link StrolchTransaction} by evaluating if the given argument has a realm defined, if not, then the
* realm from the user certificate is used. The action for the TX is this implementation's class name. This
* transaction should be used in a try-with-resource clause so it is properly closed
*
* @param arg
* the {@link ServiceArgument}
* @param action
* the action to use for the opened TX
* @param readOnly
* flag to denote if this TX should be read only
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openArgOrUserTx(ServiceArgument arg, String action, boolean readOnly)
throws StrolchException {
return openTx(getArgOrUserRealm(arg), action, readOnly);
}
/**
* Opens a {@link StrolchTransaction} for the given realm. This transaction should be used in a try-with-resource
* clause so it is properly closed
*
* @param realm
* the name of the realm
* @param action
* the action to use for the opened TX
* @param readOnly
* flag to denote if this TX should be read only
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openTx(String realm, String action, boolean readOnly) throws StrolchException {
return getRealm(realm).openTx(getCertificate(), action, readOnly);
}
/**
* Opens a {@link StrolchTransaction} for the given realm. This transaction should be used in a try-with-resource
* clause so it is properly closed
*
* @param realm
* the name of the realm
* @param action
* the action to use for the opened TX
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openTx(String realm, String action) throws StrolchException {
return getRealm(realm).openTx(getCertificate(), action, false);
}
/**
* Opens a {@link StrolchTransaction} where the realm retrieved using
* {@link ComponentContainer#getRealm(Certificate)}, the action for the TX is this implementation's class name. This
* transaction should be used in a try-with-resource clause so it is properly closed
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openUserTx() throws StrolchException {
return getRealm().openTx(getCertificate(), getClass(), false);
}
/**
* Opens a {@link StrolchTransaction} where the realm retrieved using
* {@link ComponentContainer#getRealm(Certificate)}, the action for the TX is this implementation's class name. This
* transaction should be used in a try-with-resource clause so it is properly closed
*
* @param readOnly
* flag to denote if this TX should be read only
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openUserTx(boolean readOnly) throws StrolchException {
return getRealm().openTx(getCertificate(), getClass(), readOnly);
}
/**
* Opens a {@link StrolchTransaction} where the realm retrieved using
* {@link ComponentContainer#getRealm(Certificate)}. This transaction should be used in a try-with-resource clause
* so it is properly closed
*
* @param action
* the action to use for the opened TX
*
* @return the open {@link StrolchTransaction}
*
* @throws StrolchException
* if the {@link StrolchRealm} does not exist with the given name
*/
protected StrolchTransaction openUserTx(String action) throws StrolchException {
return getRealm().openTx(getCertificate(), action, false);
}
/**
* Performs the given {@link SystemAction} as a system user with the given username
*
* @param username
* the name of the system user to perform the action as
* @param action
* the action to perform
*
* @throws PrivilegeException
* if the user does not exist, or is not a system user
* @throws Exception
* if anything else goes wrong during execution
*/
protected void runAs(String username, SystemAction action) throws PrivilegeException, Exception {
getPrivilegeHandler().runAs(username, action);
}
/**
* Performs the given {@link SystemAction} as a system user with the given username
*
* @param username
* the name of the system user to perform the action as
* @param action
* the action to perform
*
* @return the result
*
* @throws PrivilegeException
* if the user does not exist, or is not a system user
* @throws Exception
* if anything else goes wrong during execution
*/
protected V runWithResult(String username, SystemActionWithResult action)
throws PrivilegeException, Exception {
return getPrivilegeHandler().runWithResult(username, action);
}
/**
* Performs the given {@link PrivilegedRunnable} as a system user with the given username
*
* @param username
* the name of the system user to perform the action as
* @param runnable
* the runnable to perform
*
* @throws PrivilegeException
* if the user does not exist, or is not a system user
* @throws Exception
* if anything else goes wrong during execution
*/
protected void runAs(String username, PrivilegedRunnable runnable) throws PrivilegeException, Exception {
getPrivilegeHandler().runAs(username, runnable);
}
/**
* Performs the given {@link PrivilegedRunnableWithResult} as a system user with the given username
*
* @param username
* the name of the system user to perform the action as
* @param runnable
* the runnable to perform
*
* @return the result
*
* @throws PrivilegeException
* if the user does not exist, or is not a system user
* @throws Exception
* if anything else goes wrong during execution
*/
protected V runWithResult(String username, PrivilegedRunnableWithResult runnable)
throws PrivilegeException, Exception {
return getPrivilegeHandler().runWithResult(username, runnable);
}
/**
* Performs the given {@link SystemAction} as the privileged system user {@link StrolchConstants#SYSTEM_USER_AGENT}
*
* @param action
* the action to perform
*
* @throws PrivilegeException
* if the agent user does not exist, or is not a system user
* @throws Exception
* if anything else goes wrong during execution
*/
protected void runAsAgent(SystemAction action) throws PrivilegeException, Exception {
getPrivilegeHandler().runAsAgent(action);
}
/**
* Performs the given {@link SystemAction} as the privileged system user {@link StrolchConstants#SYSTEM_USER_AGENT}
*
* @param action
* the action to perform
*
* @return the result
*
* @throws PrivilegeException
* if the agent user does not exist, or is not a system user
* @throws Exception
* if anything else goes wrong during execution
*/
protected V runAsAgentWithResult(SystemActionWithResult action) throws PrivilegeException, Exception {
return getPrivilegeHandler().runAsAgentWithResult(action);
}
/**
* Performs the given {@link PrivilegedRunnable} as the privileged system user
* {@link StrolchConstants#SYSTEM_USER_AGENT}
*
* @param runnable
* the action to perform
*
* @throws PrivilegeException
* if the agent user does not exist, or is not a system user
* @throws Exception
* if anything else goes wrong during execution
*/
protected void runAsAgent(PrivilegedRunnable runnable) throws PrivilegeException, Exception {
getPrivilegeHandler().runAsAgent(runnable);
}
/**
* Performs the given {@link PrivilegedRunnableWithResult} as the privileged system user
* {@link StrolchConstants#SYSTEM_USER_AGENT}
*
* @param runnable
* the action to perform
*
* @return the result
*
* @throws PrivilegeException
* if the agent user does not exist, or is not a system user
* @throws Exception
* if anything else goes wrong during execution
*/
protected V runAsAgentWithResult(PrivilegedRunnableWithResult runnable)
throws PrivilegeException, Exception {
return getPrivilegeHandler().runAsAgentWithResult(runnable);
}
/**
* This method is final as it enforces that the argument is valid, and catches all exceptions and enforces that a
* service result is returned. A concrete implementation will implement the business logic in
* {@link #internalDoService(ServiceArgument)}
*/
@Override
public final U doService(T argument) {
if (isArgumentRequired() && argument == null) {
String msg = "Failed to perform service {0} because no argument was passed although it is required!";
msg = MessageFormat.format(msg, getClass());
logger.error(msg);
U result = getResultInstance();
result.setState(ServiceResultState.EXCEPTION);
result.setMessage(msg);
return result;
}
try {
U serviceResult = internalDoService(argument);
if (serviceResult == null) {
String msg = "Service {0} is not properly implemented as it returned a null result!";
msg = MessageFormat.format(msg, this.getClass().getName());
throw new StrolchException(msg);
}
return serviceResult;
} catch (StrolchUserMessageException e) {
U result = getResultInstance();
result.setMessage(e.getMessage());
result.setState(ServiceResultState.WARNING);
result.setI18nMessage(e.getI18n());
return result;
} catch (Exception e) {
U result = getResultInstance();
result.setMessage(e.getMessage());
Throwable rootCause = getRootCause(e);
if (rootCause instanceof StrolchUserMessageException) {
result.setState(ServiceResultState.WARNING);
result.setI18nMessage(((StrolchUserMessageException) rootCause).getI18n());
return result;
}
result.setState(ServiceResultState.EXCEPTION);
result.setThrowable(e);
return result;
}
}
/**
* Returns true if this Service requires an argument
*
* @return if true, then an argument must be set to execute the service. If the argument is missing, then the
* service execution fails immediately
*/
protected boolean isArgumentRequired() {
return true;
}
/**
* This method is called if the service execution fails and an instance of the expected {@link ServiceResult} is
* required to return to the caller
*
* @return an instance of the {@link ServiceResult} returned by this implementation
*/
protected abstract U getResultInstance();
/**
* Method to easily instantiate an instance of the {@link ServiceArgument} for this concrete service implementation
*
* @return an instance of the {@link ServiceArgument} returned by this implementation
*/
public abstract T getArgumentInstance();
/**
* Internal method to perform the {@link Service}. The implementor does not need to handle exceptions as this is
* done in the {@link #doService(ServiceArgument)} which calls this method
*
* @param arg
* the {@link ServiceArgument} containing the arguments to perform the concrete service
*
* @return a {@link ServiceResult} which denotes the execution state of this {@link Service}
*
* @throws Exception
* if something went wrong. The caller will catch and handle the {@link ServiceResult}
*/
protected abstract U internalDoService(T arg) throws Exception;
/**
* @see li.strolch.privilege.model.Restrictable#getPrivilegeName()
*/
@Override
public String getPrivilegeName() {
return Service.class.getName();
}
/**
* @see li.strolch.privilege.model.Restrictable#getPrivilegeValue()
*/
@Override
public String getPrivilegeValue() {
return this.getClass().getName();
}
}