package de.tum.in.i22.uc.pdp.core; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.tum.in.i22.uc.cm.datatypes.interfaces.IResponse; import de.tum.in.i22.uc.pdp.PxpManager; import de.tum.in.i22.uc.pdp.core.condition.Condition; import de.tum.in.i22.uc.pdp.core.condition.TimeAmount; import de.tum.in.i22.uc.pdp.core.exceptions.InvalidMechanismException; import de.tum.in.i22.uc.pdp.core.shared.Decision; import de.tum.in.i22.uc.pdp.core.shared.Event; import de.tum.in.i22.uc.pdp.core.shared.IPdpAuthorizationAction; import de.tum.in.i22.uc.pdp.core.shared.IPdpExecuteAction; import de.tum.in.i22.uc.pdp.core.shared.IPdpMechanism; import de.tum.in.i22.uc.pdp.xsd.AuthorizationActionType; import de.tum.in.i22.uc.pdp.xsd.ExecuteAsyncActionType; import de.tum.in.i22.uc.pdp.xsd.MechanismBaseType; import de.tum.in.i22.uc.pdp.xsd.PreventiveMechanismType; public class Mechanism extends Thread implements IPdpMechanism { private static Logger log = LoggerFactory.getLogger(Mechanism.class); private String mechanismName = null; private String description = null; private long lastUpdate = 0; private long timestepSize = 0; private long timestep = 0; private EventMatch triggerEvent = null; private Condition condition = null; private IPdpAuthorizationAction authorizationAction = null; private List<IPdpExecuteAction> executeAsyncActions = new ArrayList<IPdpExecuteAction>(); private PolicyDecisionPoint pdp = null; public boolean isStarted = false; // private Thread updateThread = null; private PxpManager _pxpManager; public Mechanism() { } public Mechanism(MechanismBaseType mech, PolicyDecisionPoint pdp) throws InvalidMechanismException { log.debug("Preparing mechanism from MechanismBaseType"); this.pdp = pdp; if (pdp==null){ log.error("Impossible to take proper decision with a null pdp. failing miserably"); throw new RuntimeException(); } this._pxpManager=pdp.getPxpManager(); this.mechanismName = mech.getName(); this.description = mech.getDescription(); this.lastUpdate = 0; this.timestepSize = mech.getTimestep().getAmount() * TimeAmount .getTimeUnitMultiplier(mech.getTimestep().getUnit()); this.timestep = 0; if (mech instanceof PreventiveMechanismType) { PreventiveMechanismType curMech = (PreventiveMechanismType) mech; log.debug("Processing PreventiveMechanism"); this.triggerEvent = new EventMatch(curMech.getTrigger(), this); ActionDescriptionStore ads = pdp.getActionDescriptionStore(); ads.addMechanism(this); // TODO: subscription to PEP?! log.debug( "Preparing AuthorizationAction from List<AuthorizationActionType>: {} entries", curMech.getAuthorizationAction().size()); HashMap<String, AuthorizationAction> authActions = new HashMap<String, AuthorizationAction>(); for (AuthorizationActionType auth : curMech .getAuthorizationAction()) { log.debug("Found authAction {}", auth.getName()); if (auth.isSetStart() || curMech.getAuthorizationAction().size() == 1) authActions.put("start", new AuthorizationAction(auth)); else authActions.put(auth.getName(), new AuthorizationAction( auth)); } log.debug("Preparing hierarchy of authorizationActions (list: {})", authActions.size()); this.authorizationAction = authActions.get("start"); if (curMech.getAuthorizationAction().size() > 1) { IPdpAuthorizationAction curAuth = this.authorizationAction; log.debug("starting with curAuth: {}", curAuth.getName()); do { log.debug("searching for fallback={}", curAuth.getFallbackName()); if (!curAuth.getFallbackName().equalsIgnoreCase("allow") && !curAuth.getFallbackName().equalsIgnoreCase( "inhibit")) { IPdpAuthorizationAction fallbackAuth = authActions .get(curAuth.getFallbackName()); if (fallbackAuth == null) { log.error( "Requested fallback authorizationAction {} not found!", curAuth.getFallbackName()); throw new InvalidMechanismException( "Requested fallback authorizationAction not specified"); } curAuth.setFallback(fallbackAuth); log.debug(" set fallback to {}", curAuth.getFallback() .getName()); } else { if (curAuth.getFallbackName().equalsIgnoreCase("allow")) { curAuth.setFallback(AuthorizationAction.AUTHORIZATION_ALLOW); } log.debug(" set fallback to static {}", curAuth .getFallback().getName()); break; } curAuth = curAuth.getFallback(); } while (true); } log.debug("AuthorizationActions successfully processed."); } this.condition = new Condition(mech.getCondition(), this); log.debug("Processing executeAsyncActions"); // Processing synchronous executeActions for allow for (ExecuteAsyncActionType execAction : mech.getExecuteAsyncAction()) { this.executeAsyncActions.add(new ExecuteAction(execAction)); } } public boolean init() { log.debug("Initializing mechanism update thread"); this.lastUpdate = System.currentTimeMillis(); // this.updateThread = new Thread(this); // this.updateThread.start(); // Populate pip depending on the current condition this.condition.operator.initOperatorForMechanism(this); return (isStarted = true); } @Override public String getMechanismName() { return mechanismName; } public void setMechanismName(String name) { this.mechanismName = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public IPdpAuthorizationAction getAuthorizationAction() { return authorizationAction; } @Override public void setAuthorizationAction( IPdpAuthorizationAction authorizationAction) { this.authorizationAction = authorizationAction; } @Override public List<IPdpExecuteAction> getExecuteAsyncActions() { return executeAsyncActions; } public void setExecuteAsyncActions( List<IPdpExecuteAction> executeAsyncActions) { this.executeAsyncActions = executeAsyncActions; } public EventMatch getTriggerEvent() { return triggerEvent; } public void setTriggerEvent(EventMatch triggerEvent) { this.triggerEvent = triggerEvent; } @Override public long getTimestepSize() { return timestepSize; } @Override public void setTimestepSize(long timestepSize) { this.timestepSize = timestepSize; } @Override public boolean revoke() { // this.updateThread.interrupt(); this.interrupt(); return true; } public synchronized Decision notifyEvent(Event curEvent, Decision d) { log.debug("updating mechanism [{}]", this.getMechanismName()); if (this.triggerEvent.eventMatches(curEvent)) { log.info("Event matches -> evaluating condition"); boolean ret = this.condition.evaluate(curEvent); if (ret) { log.info("Condition satisfied; merging mechanism into decision"); d.processMechanism(this, curEvent); } else log.info("condition NOT satisfied"); } return d; } private synchronized boolean mechanismUpdate() { // TODO improve accuracy to // microseconds? long now = System.currentTimeMillis(); long elapsedLastUpdate = now - this.lastUpdate; long difference = elapsedLastUpdate - this.timestepSize / 1000; if (difference < 0) { // Aborting update because the timestep has not // yet passed log.trace( "[{}] Timestep remaining {} -> timestep has not yet passed", this.mechanismName, difference); log.trace("##############################################################################################################"); return false; } // Correct time substracting possible delay in the execution because // difference between timestep and last time // mechanism was updated will not be exactly the timestepSize this.lastUpdate = now - difference; if (difference > this.timestepSize) { log.warn( "[{}] Timestep difference is larger than mechanism's timestep size => we missed to evaluate at least one timestep!!", this.mechanismName); log.warn("--------------------------------------------------------------------------------------------------------------"); } timestep++; log.debug("////////////////////////////////////////////////////////////////////////////////////////////////////////////"); log.debug("["+this.mechanismName+"] Null-Event updating {}. timestep at interval of {} us", this.timestep, this.timestepSize); boolean conditionValue = this.condition.evaluate(null); log.debug("conditionValue: {}", conditionValue); log.debug("////////////////////////////////////////////////////////////////////////////////////////////////////////////"); return conditionValue; } @Override public void run() { long sleepValue = this.timestepSize / 1000; log.info("Started mechanism update thread usleep={} ms", sleepValue); while (!isInterrupted()) { try { boolean mechanismValue = this.mechanismUpdate(); if (mechanismValue) { log.info("Mechanism condition satisfied; triggered optional executeActions"); for (IPdpExecuteAction execAction : this .getExecuteAsyncActions()) { if (execAction.getProcessor().equals("pep")) log.warn( "Timetriggered execution of executeAction [{}] not possible with processor PEP", execAction.getName()); else { log.debug("Execute asynchronous action [{}]", execAction.getName()); _pxpManager.execute(execAction, false); } } } if (interrupted()) { log.info("Mechanism thread was interrupted. terminating..."); return; } sleep(sleepValue); } catch (InterruptedException e) { log.info( "[InterruptedException] Mechanism [{}] was interrupted. terminating...", this.getMechanismName()); return; } } } @Override public String toString() { String str = "\nMechanism: name=[" + this.mechanismName + "]\n description=[" + this.description + "]"; str += "\n timestepSize=[" + timestepSize + "]"; str += "\n lastUpdate=[" + lastUpdate + "]"; str += "\n timestep=[" + timestep + "]"; str += "\n triggerEvent=[" + triggerEvent + "]"; str += "\n condition=[" + condition + "]"; str += "\n authorizationActions=[" + authorizationAction + "]"; str += "\n executeActions=[" + executeAsyncActions + "]"; return str; } @Override public IResponse getResponse() { // TODO Auto-generated method stub return null; } @Override public List<IPdpExecuteAction> getExecuteActions() { return this.executeAsyncActions; } @Override public void setExecuteActions(ArrayList<IPdpExecuteAction> mExecuteActions) { this.executeAsyncActions = mExecuteActions; } @Override public void addExecuteAction(IPdpExecuteAction mExecuteActionTmp) { this.executeAsyncActions.add(mExecuteActionTmp); } @Override public PolicyDecisionPoint getPolicyDecisionPoint() { return pdp; } }