/* * Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * * 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.model.PolicyContainer; import li.strolch.model.policy.PolicyDef; import li.strolch.model.policy.PolicyDefs; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.policy.PolicyHandler; import li.strolch.policy.StrolchPolicy; import li.strolch.privilege.base.PrivilegeException; import li.strolch.privilege.handler.SystemUserAction; import li.strolch.privilege.model.Restrictable; /** * <p> * Implementation of the Command Pattern to create re-usable components which are performed during * {@link StrolchTransaction StrolchTransactions} as part of the execution of {@link Service Services} * </p> * * <p> * <b>Note:</b> Do not call {@link #doCommand()} from {@link Service Services} or other places. Add {@link Command} * instances to a {@link StrolchTransaction} by calling {@link StrolchTransaction#addCommand(Command)} * </p> * * @author Robert von Burg <eitch@eitchnet.ch> */ public abstract class Command implements Restrictable { protected static final Logger logger = LoggerFactory.getLogger(Command.class); private final ComponentContainer container; private final StrolchTransaction tx; /** * Instantiate a new {@link Command} * * @param container * the {@link ComponentContainer} to access components at runtime * @param tx */ public Command(ComponentContainer container, StrolchTransaction tx) { this.container = container; this.tx = tx; } /** * Allows the concrete {@link Command} implementation access to {@link StrolchComponent StrolchComponents} at * runtime * * @param clazz * the type of component to be returned * * @return the component with the given {@link Class} which is registered on the {@link ComponentContainer} * * @throws IllegalArgumentException * if the component with the given class does not exist */ protected <V> V getComponent(Class<V> clazz) throws IllegalArgumentException { return this.container.getComponent(clazz); } /** * @return the container */ protected ComponentContainer getContainer() { return this.container; } /** * Returns a {@link StrolchPolicy} instance from the given parameters * * @param policyClass * the policy type to return. The simple name of the class determines the type of Policy to return. * @param policyDefs * the policy defs from which to get the policy by using the simple name of the policy class to determine * the type of policy to return * * @return the policy */ protected <T extends StrolchPolicy> T getPolicy(Class<T> policyClass, PolicyContainer policyContainer) { PolicyDefs policyDefs = policyContainer.getPolicyDefs(); PolicyDef policyDef = policyDefs.getPolicyDef(policyClass.getSimpleName()); PolicyHandler policyHandler = getComponent(PolicyHandler.class); @SuppressWarnings("unchecked") T policy = (T) policyHandler.getPolicy(policyDef, tx()); return policy; } /** * Performs the given {@link SystemUserAction} as a system user with the given username. Returns the action for * chaining calls * * @param username * the name of the system user to perform the action as * @param action * the action to perform * * @return the action performed for chaining calls * * @throws PrivilegeException */ protected <V extends SystemUserAction> V runAs(String username, V action) throws PrivilegeException { return this.container.getPrivilegeHandler().runAsSystem(username, action); } /** * Returns the {@link StrolchTransaction} bound to this {@link Command}'s runtime * * @return the {@link StrolchTransaction} bound to this {@link Command}'s runtime */ protected StrolchTransaction tx() { return this.tx; } /** * @see li.strolch.privilege.model.Restrictable#getPrivilegeName() */ @Override public String getPrivilegeName() { return Command.class.getName(); } /** * @see li.strolch.privilege.model.Restrictable#getPrivilegeValue() */ @Override public Object getPrivilegeValue() { return this.getClass().getName(); } /** * To ensure that as few possibilities for exceptions as possible occur when {@link #doCommand()} is called, the * {@link Command} should verify any input data so that a {@link #doCommand()} can be performed without exceptions */ public abstract void validate(); /** * <p> * Clients implement this method to perform the work which is to be done in this {@link Command}. * </p> * * <p> * <b>Note:</b> Do not call this method directly, this method is called by the {@link StrolchTransaction} when the * transaction is committed. Add this {@link Command} to the transaction by calling * {@link StrolchTransaction#addCommand(Command)} * </p> */ public abstract void doCommand(); /** * <p> * Should the transaction fail, either due to a {@link Command} throwing an exception when {@link #validate()} is * called, or while committing the transaction, then this method should properly undo any changes it has done. It is * imperative that this method does not throw further exceptions and that the state to be rolled back is remembered * in the Command during committing * </p> */ public abstract void undo(); }