package de.tum.in.i22.uc.pdp.core;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ae.javax.xml.bind.JAXBContext;
import ae.javax.xml.bind.JAXBElement;
import ae.javax.xml.bind.JAXBException;
import ae.javax.xml.bind.UnmarshalException;
import ae.javax.xml.bind.Unmarshaller;
import de.tum.in.i22.uc.cm.datatypes.basic.XmlPolicy;
import de.tum.in.i22.uc.cm.interfaces.IPdp2Pip;
import de.tum.in.i22.uc.pdp.PxpManager;
import de.tum.in.i22.uc.pdp.core.exceptions.InvalidMechanismException;
import de.tum.in.i22.uc.pdp.core.shared.Constants;
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.IPdpMechanism;
import de.tum.in.i22.uc.pdp.core.shared.IPolicyDecisionPoint;
import de.tum.in.i22.uc.pdp.xsd.MechanismBaseType;
import de.tum.in.i22.uc.pdp.xsd.PolicyType;
public class PolicyDecisionPoint implements IPolicyDecisionPoint, Serializable
{
private static Logger _logger =LoggerFactory.getLogger(PolicyDecisionPoint.class);
private static final long serialVersionUID =-6823961095919408237L;
private static IPdp2Pip _pip;
private static ActionDescriptionStore _actionDescriptionStore =null;
private final HashMap<String, ArrayList<IPdpMechanism>> _policyTable =new HashMap<String, ArrayList<IPdpMechanism>>();
private static PxpManager _pxpManager = null;
private static IPolicyDecisionPoint sInstance = null;
private PolicyDecisionPoint()
{
_actionDescriptionStore=new ActionDescriptionStore();
_pxpManager=new PxpManager();
}
private PolicyDecisionPoint(IPdp2Pip pip, PxpManager pxpManager)
{
_pxpManager=pxpManager;
_actionDescriptionStore=new ActionDescriptionStore();
_pip=pip;
}
public static IPolicyDecisionPoint getInstance()
{
if(sInstance!=null) return sInstance;
sInstance = new PolicyDecisionPoint();
return sInstance;
}
public static IPolicyDecisionPoint getInstance(IPdp2Pip pip, PxpManager pxpManager)
{
if(sInstance!=null) return sInstance;
sInstance = new PolicyDecisionPoint(pip, pxpManager);
return sInstance;
}
@Override
public boolean deployPolicyXML(XmlPolicy XMLPolicy)
{
_logger.debug("deployPolicyXML (before) : " + XMLPolicy.getName());
InputStream is=new ByteArrayInputStream(XMLPolicy.getXml().getBytes());
_logger.debug("deployPolicyXML (IS created) : " + XMLPolicy.getName());
boolean b=deployXML(is);
_logger.debug("deployPolicyXML (after) : " + XMLPolicy.getName());
return b;
}
@Override
public boolean deployPolicyURI(String policyFilename)
{
if(policyFilename.endsWith(".xml"))
{
InputStream inp=null;
try
{
inp=new FileInputStream(policyFilename);
}
catch(FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return deployXML(inp);
}
_logger.warn("Unsupported message format of policy! " + policyFilename);
return false;
}
public boolean deployXML(InputStream inp)
{
if(inp == null) return false;
try
{
// SA, 11.02.2015: The following line leads to code that will throw and catch a
// NullPointerException. Just ignore that.
//
// try
// {
// XmlSchema s = null;
// s.location();
// }
// catch (NullPointerException e) {}catch (NoSuchMethodError e)
// {
// ...
// }
//
JAXBContext jc=JAXBContext.newInstance("de.tum.in.i22.uc.pdp.xsd");
Unmarshaller u=jc.createUnmarshaller();
// u.setSchema(null);
JAXBElement<?> poElement=(JAXBElement<?>)u.unmarshal(inp);
PolicyType curPolicy=(PolicyType)poElement.getValue();
_logger.debug("curPolicy [name={}]: {}", curPolicy.getName(), curPolicy.toString());
List<MechanismBaseType> mechanisms=curPolicy.getDetectiveMechanismOrPreventiveMechanism();
if(_policyTable.containsKey(curPolicy.getName()))
{
// log.error("Policy [{}] already deployed! Aborting...",
// curPolicy.getName());
// return false;
}
for(MechanismBaseType mech : mechanisms)
{
try
{
_logger.debug("Processing mechanism: {}", mech.getName());
IPdpMechanism curMechanism=new Mechanism(mech, this);
ArrayList<IPdpMechanism> mechanismList=_policyTable.get(curPolicy.getName());
if(mechanismList == null) mechanismList=new ArrayList<IPdpMechanism>();
if(mechanismList.contains(curMechanism))
{
_logger.error("Mechanism [{}] is already deployed for policy [{}]", curMechanism.getMechanismName(), curPolicy.getName());
continue;
}
mechanismList.add(curMechanism);
_policyTable.put(curPolicy.getName(), mechanismList);
_logger.debug("Starting mechanism update thread...");
if(curMechanism instanceof Mechanism)
{
((Mechanism)curMechanism).init();
((Mechanism)curMechanism).start();
}
_logger.info("Mechanism {} started...", curMechanism.getMechanismName());
}
catch(InvalidMechanismException e)
{
_logger.error("Invalid mechanism specified: {}", e.getMessage());
return false;
}
}
return true;
}
catch(UnmarshalException e)
{
_logger.error("Syntax error in policy: " + e.getMessage());
}
catch(JAXBException | ClassCastException e)
{
e.printStackTrace();
}
return false;
}
@Override
public boolean revokePolicy(String policyName)
{
boolean ret=false;
if(_policyTable == null)
{
_logger.error("Empty Policy Table. impossible to revoke policy");
return false;
}
List<IPdpMechanism> mlist=_policyTable.get(policyName);
if(mlist == null) return false;
for(IPdpMechanism mech : mlist)
{
_logger.info("Revoking mechanism: {}", mech.getMechanismName());
ret=mech.revoke();
}
return ret;
}
@Override
public boolean revokeMechanism(String policyName, String mechName)
{
boolean ret=false;
if(_policyTable == null)
{
_logger.error("Empty Policy Table. impossible to revoke policy");
return false;
}
ArrayList<IPdpMechanism> mechanisms=_policyTable.get(policyName);
if(mechanisms != null)
{
IPdpMechanism mech=null;
for(IPdpMechanism m : mechanisms)
{
if(m.getMechanismName().equals(mechName))
{
_logger.info("Revoking mechanism: {}", m.getMechanismName());
ret=m.revoke();
mech=m;
break;
}
}
if(mech != null)
{
mechanisms.remove(mech);
if(mech instanceof Mechanism)
{
_actionDescriptionStore.removeMechanism(((Mechanism)mech).getTriggerEvent().getAction());
}
}
}
return ret;
}
@Override
public Decision notifyEvent(Event event)
{
ArrayList<EventMatch> eventMatchList=_actionDescriptionStore.getEventList(event.getEventAction());
if(eventMatchList == null) eventMatchList=new ArrayList<EventMatch>();
_logger.debug("Searching for subscribed condition nodes for event=[{}] -> subscriptions: {}", event.getEventAction(), eventMatchList.size());
for(EventMatch eventMatch : eventMatchList)
{
_logger.info("Processing EventMatchOperator for event [{}]", eventMatch.getAction());
eventMatch.evaluate(event);
}
ArrayList<Mechanism> mechanismList=_actionDescriptionStore.getMechanismList(event.getEventAction());
if(mechanismList == null) mechanismList=new ArrayList<Mechanism>();
_logger.debug("Searching for triggered mechanisms for event=[{}] -> subscriptions: {}", event.getEventAction(), mechanismList.size());
Decision d=new Decision(new AuthorizationAction("default", Constants.AUTHORIZATION_ALLOW), _pxpManager);
for(Mechanism mech : mechanismList)
{
_logger.info("Processing mechanism [{}] for event [{}]", mech.getMechanismName(), event.getEventAction());
mech.notifyEvent(event, d);
}
return d;
}
@Override
public Map<String, List<String>> listDeployedMechanisms()
{
Map<String, List<String>> map=new HashMap<String, List<String>>();
for(String policyName : _policyTable.keySet())
{
List<String> mechanismList=new ArrayList<String>();
for(IPdpMechanism m : _policyTable.get(policyName))
{
mechanismList.add(m.getMechanismName());
}
map.put(policyName, mechanismList);
}
return map;
}
@Override
public IPdp2Pip getPip()
{
return _pip;
}
@Override
public ActionDescriptionStore getActionDescriptionStore()
{
return _actionDescriptionStore;
}
@Override
public PxpManager getPxpManager()
{
return _pxpManager;
}
@Override
public void stop()
{
// TODO Auto-generated method stub
Set<String> _policyTableKeys=this._policyTable.keySet();
Iterator<String> _policyTableKeysIt=_policyTableKeys.iterator();
while(_policyTableKeysIt.hasNext())
{
String _policyTableKey=_policyTableKeysIt.next();
ArrayList<IPdpMechanism> mechanisms=_policyTable.get(_policyTableKey);
Iterator<IPdpMechanism> mechanismsIt=mechanisms.iterator();
while(mechanismsIt.hasNext())
{
IPdpMechanism mechanism=mechanismsIt.next();
if(mechanism instanceof Runnable)
{
((Thread)mechanism).interrupt();
}
}
}
this._policyTable.clear();
}
}