/** * Copyright (c) Members of the EGEE Collaboration. 2006-2009. * See http://www.eu-egee.org/partners/ for details on the copyright holders. * * 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 org.glite.authz.pap.distribution; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; import javax.xml.rpc.ServiceException; import org.glite.authz.pap.common.Pap; import org.glite.authz.pap.common.xacml.impl.TypeStringUtils; import org.glite.authz.pap.papmanagement.PapContainer; import org.glite.authz.pap.papmanagement.PapManager; import org.opensaml.xacml.XACMLObject; import org.opensaml.xacml.policy.PolicySetType; import org.opensaml.xacml.policy.PolicyType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class implements the distribution module, that means running a thread which regularly polls * remote paps to fetch policies. * <p> * Start the thread that polls remote paps by calling the * {@link DistributionModule#startDistributionModule()} method and stop it by calling the * {@link DistributionModule#stopDistributionModule()} method. * <p> * The {@link DistributionModule#refreshCache(Pap)} method can be used to force a refresh of the * remote paps cache asynchronously. */ public class DistributionModule extends Thread { /** lock used when the cache of a pap is refreshed. */ public static final Object storePoliciesLock = new Object(); private static final Logger log = LoggerFactory.getLogger(DistributionModule.class); private static DistributionModule instance = null; private long sleepTime; private boolean stayRunning = true; private DistributionModule() { initialize(); } public static DistributionModule getInstance() { if (instance == null) instance = new DistributionModule(); return instance; } /** * Refreshes the policies of a pap, that means fetching the policies and storing them in the * repository. If the given pap is not remote then nothing happens. * * @param pap * * @throws RemoteException * @throws ServiceException */ public static void refreshCache(Pap pap) throws RemoteException, ServiceException { log.info("Refreshing cache of remote PAP " + pap.getAlias()); List<XACMLObject> papPolicies = getPoliciesFromPap(pap); log.info(String.format("Retrieved %d XACML objects from PAP %s (%s)", papPolicies.size(), pap.getAlias(), pap.getEndpoint())); storePapPolicies(pap, papPolicies); } /** * Fetches policies from a remote pap. * * @param remotePap the remote pap to fetch policies from. * @return the list of policy sets and policies of the pap. The first element is the root policy * set of the pap. Returns an empty list if the pap wasn't a remote pap. * * @throws RemoteException * @throws ServiceException */ private static List<XACMLObject> getPoliciesFromPap(Pap remotePap) throws RemoteException, ServiceException { if (!remotePap.isRemote()) { log.error("Attempting to fetch policies from the local pap: " + remotePap.getAlias()); return new ArrayList<XACMLObject>(0); } PAPClient client = new PAPClient(remotePap.getEndpoint()); List<XACMLObject> papPolicies = client.retrievePolicies(); return papPolicies; } /** * Replace the policy cache of the given pap with the given policies. * * @param pap * @param papPolicies */ private static void storePapPolicies(Pap pap, List<XACMLObject> papPolicies) { if (papPolicies.isEmpty()) { return; } log.debug(String.format("Storing policies for PAP %s (id=%s)", pap.getAlias(), pap.getId())); PapManager papManager = PapManager.getInstance(); PapContainer papContainer = papManager.getPapContainer(pap.getAlias()); synchronized (storePoliciesLock) { papContainer.deleteAllPolicies(); papContainer.deleteAllPolicySets(); XACMLObject papRoot = papPolicies.get(0); if (papRoot instanceof PolicySetType) { ((PolicySetType) papRoot).setPolicySetId(papContainer.getPap().getId()); for (XACMLObject xacmlObject : papPolicies) { if (xacmlObject instanceof PolicySetType) { PolicySetType policySet = (PolicySetType) xacmlObject; papContainer.storePolicySet(policySet); log.debug(String.format("Stored PolicySet \"%s\" into pap \"%s\"", policySet.getPolicySetId(), pap.getAlias())); } else if (xacmlObject instanceof PolicyType) { PolicyType policy = (PolicyType) xacmlObject; papContainer.storePolicy(policy); log.debug(String.format("Stored Policy \"%s\" into pap \"%s\"", policy.getPolicyId(), pap.getAlias())); } else { log.error(String.format("Invalid object (not a Policy or PolicySet) received from PAP %s (%s)", pap.getAlias(), pap.getEndpoint())); } TypeStringUtils.releaseUnneededMemory(xacmlObject); } } else { log.error(String.format("The root of the policy tree is not a PolicySet (papAlias=%s, endpoint=%s)", pap.getAlias(), pap.getEndpoint())); } } } /* * (non-Javadoc) * * @see java.lang.Thread#run() */ public void run() { while (stayRunning) { try { while (!this.isInterrupted()) { log.info("Starting refresh cache thread..."); for (Pap pap : PapManager.getInstance().getRemotePaps()) { if (this.isInterrupted()) break; try { refreshCache(pap); } catch (RemoteException e) { log.error(String.format("Error connecting to %s (%s): %s", pap.getAlias(), pap.getEndpoint(), e.getMessage())); } catch (ServiceException e) { log.error(String.format("Cannot connect to: %s (%s)", pap.getAlias(), pap.getEndpoint(), e.getMessage())); } } log.info("Refresh cache thread done."); sleep(sleepTime); } } catch (InterruptedException e) {} } } public void startDistributionModule() { this.start(); } public void setSleepTime(long seconds) { sleepTime = seconds * 1000; this.interrupt(); } public void stopDistributionModule() { stayRunning = false; this.interrupt(); while (this.isAlive()); } protected void initialize() { log.info("Initilizing distribution module..."); sleepTime = DistributionConfiguration.getInstance().getPollIntervall() * 1000; } }