001/*
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: PolicyEvaluator.java,v 1.19 2010/01/14 23:18:35 dillidorai Exp $
026 *
027 * Portions Copyrighted 2011-2015 ForgeRock AS.
028 */
029
030package com.sun.identity.policy;
031
032import static org.forgerock.openam.utils.CollectionUtils.asSet;
033
034import javax.security.auth.Subject;
035import java.security.AccessController;
036import java.security.Principal;
037import java.util.Collections;
038import java.util.Enumeration;
039import java.util.HashMap;
040import java.util.HashSet;
041import java.util.Iterator;
042import java.util.List;
043import java.util.Map;
044import java.util.Set;
045
046import com.iplanet.am.sdk.AMCommonUtils;
047import com.iplanet.am.sdk.AMException;
048import com.iplanet.am.sdk.AMStoreConnection;
049import com.iplanet.am.sdk.AMUser;
050import com.iplanet.am.util.Cache;
051import com.iplanet.am.util.SystemProperties;
052import com.iplanet.sso.SSOException;
053import com.iplanet.sso.SSOToken;
054import com.iplanet.sso.SSOTokenListener;
055import com.sun.identity.entitlement.Application;
056import com.sun.identity.entitlement.ApplicationManager;
057import com.sun.identity.entitlement.Entitlement;
058import com.sun.identity.entitlement.EntitlementException;
059import com.sun.identity.entitlement.Evaluator;
060import com.sun.identity.entitlement.opensso.SubjectUtils;
061import com.sun.identity.monitoring.Agent;
062import com.sun.identity.monitoring.MonitoringUtil;
063import com.sun.identity.monitoring.SsoServerPolicySvcImpl;
064import com.sun.identity.policy.interfaces.Condition;
065import com.sun.identity.policy.interfaces.PolicyListener;
066import com.sun.identity.security.AdminTokenAction;
067import com.sun.identity.shared.debug.Debug;
068import com.sun.identity.shared.stats.Stats;
069import com.sun.identity.sm.AttributeSchema;
070import com.sun.identity.sm.DNMapper;
071import com.sun.identity.sm.ServiceManager;
072import org.forgerock.openam.entitlement.PolicyConstants;
073import org.forgerock.openam.ldap.LDAPUtils;
074
075/**
076 * The class <code>PolicyEvaluator</code> evaluates policies
077 * and provides policy decisions.
078 * @supported.api
079 * @deprecated since 12.0.0
080 */
081@Deprecated
082public class PolicyEvaluator {
083
084    /**
085     * Constant used to identity all the resources of a service type. 
086     * The resources include the sub resources of all resource prefixes of 
087     * resource type
088     *
089     * @supported.api
090     */
091    public static final String ALL_RESOURCES 
092            = "---ALL_RESOURCES---";
093
094    public static final String ADVICING_ORGANIZATION 
095            = "AdvicingOrganization";
096
097    /**
098     * Constant used to identity empty resource
099     *
100     * @supported.api
101     */
102    public static final String EMPTY_RESOURCE_NAME = "";
103
104    /**
105     * Constant used for key to pass the requested resource name canonicalized
106     * in the env map, so that Condition(s)/ResponseProvider(s) could use 
107     * the requested resource name, if necessary
108     */
109    public static final String SUN_AM_REQUESTED_RESOURCE 
110            = "sun.am.requestedResource";
111
112    /**
113     * Constant used for key to pass the requested resource name uncanonicalized
114     * in the env map, so that Condition(s)/ResponseProvider(s) could use 
115     * the requested resource name, if necessary
116     */
117    public static final String SUN_AM_ORIGINAL_REQUESTED_RESOURCE 
118            = "sun.am.requestedOriginalResource";
119
120    /**
121     * Constant used for key to pass the requested actions names
122     * in the env map, so that Condition(s)/ResponseProvider(s) could use 
123     *  the requested actions names, if necessary
124     */
125    public static final String SUN_AM_REQUESTED_ACTIONS 
126            = "sun.am.requestedActions";
127
128    /**
129     * Constant used for key to pass the realm DN in the env map, so that Condition(s)
130     * can look up the relevant <code>PolicyConfig</code> config map, if necessary.
131     * <code>LDAPFilterCondition</code> needs to use PolicyConfig config map.
132     */
133    public static final String REALM_DN = "am.policy.realmDN";
134
135    public static final String RESULTS_CACHE_SESSION_CAP 
136            = "com.sun.identity.policy.resultsCacheSessionCap";
137
138    public static int DEFAULT_RESULTS_CACHE_SESSION_CAP = 1000;
139
140    public static int resultsCacheSessionCap = DEFAULT_RESULTS_CACHE_SESSION_CAP;
141
142    public static final String RESULTS_CACHE_RESOURCE_CAP 
143            = "com.sun.identity.policy.resultsCacheResourceCap";
144
145    public static int DEFAULT_RESULTS_CACHE_RESOURCE_CAP = 100;
146
147    public static int resultsCacheResourceCap = DEFAULT_RESULTS_CACHE_RESOURCE_CAP;
148
149    private static final Debug DEBUG = PolicyManager.debug;
150    private static final boolean USE_POLICY_CACHE = true;
151    private static final boolean INCLUDE_SUPER_RESOURCE_POLCIES = true;
152    private static final long DEFAULT_USER_NSROLE_CACHE_TTL = 600000;
153
154    private String orgName;
155    private String realm;
156    private String serviceTypeName;
157    private String applicationName;
158    private ServiceType serviceType;
159    private PolicyCache policyCache;
160    private PolicyManager policyManager;
161    private ResourceIndexManager resourceIndexManager;
162
163    private HashMap booleanActionNameTrueValues; //cache
164    private HashMap booleanActionNameFalseValues; //cache
165    private Set actionNames; //all action names valid for the serviceType
166    private Set orgNames = new HashSet(); // to pass org name in envParameters
167    // used to pass service type name in envParameters
168    private Set serviceTypeNames = new HashSet(); 
169    // listener for policy decision cache
170    private PolicyDecisionCacheListener listener = null; 
171
172    /*
173     * Cache to keep the policy evaluation results
174     * Cache structure layout:
175     * 
176     * cache ----> Servicename1
177     *       ----> servicename2
178     *        ...  
179     *       ----> servicenameN
180     *
181     * servicenameI ----> Resourcename1
182     *              ----> Resourcename2
183     *              ...
184     *              ----> ResourcenameN
185     *
186     * resourcenameI ----> userssotokenidstring1
187     *               ----> userssotokenidstring2
188     *               ...
189     *               ----> userssotokenidstringN
190     *
191     * userssotokenidstringI ----> requestscope1
192     *                       ----> requestscope2
193     *
194     * requestscope1 ----> resourceresult1
195     * requestscope2 ----> resourceresult2
196     */
197    static Map policyResultsCache = new HashMap();
198
199    /*
200     * The sso token listener registry for policy decision cache. 
201     * To avoid adding multiple sso token listeners for the same 
202     * token, we use this registry to make sure the listener is 
203     * registered only once for each token. It will be unregistered 
204     * if token is expired. 
205     *
206     * Key is tokenId and value is policySSOTokenListener
207     * ssoTokenIDString : PolicySSOTokenListener
208     *
209     * Used to clean up cache on ssoToken notifications
210     */
211    public static Map ssoListenerRegistry =
212              Collections.synchronizedMap(new HashMap());
213
214    /*
215     * The policy change listener registry for policy decision cache.
216     * To avoid adding multiple listeners for the same service, we 
217     * use this registry to make sure the listener is registered only 
218     * once for each service. 
219     *
220     * Key is serviceTypeName and value is <code>PolicyDecisionCacheListener
221     * </code>
222     * serviceTypeName : PolicyDecisionCacheListener for service type
223     *
224     * Used to clean up the decision cache on policy change notification
225     */
226    private static Map<String, PolicyDecisionCacheListener> policyListenerRegistry =
227              Collections.synchronizedMap(new HashMap<String, PolicyDecisionCacheListener>());
228
229    /**
230     * The user <code>nsRole</code> attribute cache.
231     * AMSDK cache stops caching a user's nsRole attribute in 6.2
232     * due to notification issue. Adding this cache in policy to 
233     * avoid performance impact caused by the AMSDK change. This 
234     * cache uses a user's token as the key to map to the user's
235     * <code>nsRole</code> attribute values.
236     *
237     * Key is tokenId and value is set of role DN(s)
238     * ssoTokenIDString : set of role DN(s)
239     */
240    static Map userNSRoleCache = 
241              Collections.synchronizedMap(new HashMap());
242
243    // TTL value for entries in the user's nsRole attribute values.
244    private static long userNSRoleCacheTTL = 0;
245
246    /**
247     * listener object to be used in cleaning up the
248     * userNSRoleCache, subjectEvaluationCache , user role
249     * cache in LDAPRoles and policyResultsCache 
250     * upon user token  expiration.
251     */
252    public static SSOTokenListener ssoListener = 
253                                 new PolicySSOTokenListener(); 
254               
255    /*
256     * Cache for sub resources keyed by resource name 
257     * The structure is a Map of
258     * serviceType(String) : resourceNamesCache(Cache)
259     * Key for resourceNamesCache is a root resource name and value is
260     * a <code>Set</code> of sub resource names for the root resource name
261     *
262     * serviceType: resourceName : resourceNames
263     */
264    private static Map resourceNamesMap = new HashMap(); 
265
266    /**
267     * Constant key for passing organization name in the environment map during
268     * policy evaluation. The value for the key would be a <code>Set</code> 
269     * with one element of type String. The string is the name of the 
270     * organization the policy evaluator has been instantiated for.
271     */
272     static final String ORGANIZATION_NAME = "organizationName";
273
274    /**
275     * Constant key for passing service type name in the environment map during
276     * policy evaluation. The value for the key would be a <code>Set</code> 
277     * with one element of type String. The string is the name of the 
278     * <code>ServiceType</code> the  policy evaluator has been instantiated for.
279     */
280     static final String SERVICE_TYPE_NAME = "serviceTypeName";
281
282     static final Object lock = new Object();
283
284    /**
285     * Constructor to create a <code>PolicyEvaluator</code> given the <code>
286     * ServiceType</code> name.
287     *
288     * @param serviceTypeName the name of the <code>ServiceType</code> for 
289     * which this evaluator can be used.
290     * @throws SSOException if <code>SSOToken</code> used by
291     *                      <code>PolicyEvaluator</code> is invalid
292     * @throws NameNotFoundException if the service with name 
293     *                      <code>serviceTypeName</code> is not found
294     * @throws PolicyException for any other abnormal condition
295     *
296     * @supported.api
297     */
298    public PolicyEvaluator(String serviceTypeName)
299        throws SSOException, NameNotFoundException, PolicyException {
300
301        this("", serviceTypeName);
302
303        registerListener();
304    }
305
306    /**
307     * Constructor to create a <code>PolicyEvaluator</code> given organization
308     * name and the <code>ServiceType</code> name.
309     *
310     * @param orgName the name of the organization under which the evaluation
311     * is being done
312     * @param serviceTypeName the name of the <code>ServiceType</code> for 
313     * which this evaluator can be used.
314     */
315    public PolicyEvaluator(String orgName, String serviceTypeName)
316            throws SSOException, PolicyException, NameNotFoundException {
317
318        if ( (orgName == null) || (orgName.equals("/"))
319                    || (orgName.length() == 0) ) {
320            orgName = ServiceManager.getBaseDN();
321        } else {
322            orgName = com.sun.identity.sm.DNMapper.orgNameToDN(orgName);
323        }
324        this.orgName = orgName;
325
326        this.realm = com.sun.identity.sm.DNMapper.orgNameToRealmName(orgName);
327        this.serviceTypeName = serviceTypeName;
328        // Default application to be the service type, this maintains legacy behaviour.
329        this.applicationName = serviceTypeName;
330
331        this.policyCache = PolicyCache.getInstance();
332
333        ServiceTypeManager stm = ServiceTypeManager.getServiceTypeManager();
334        serviceType = stm.getServiceType(serviceTypeName);
335        policyManager = policyCache.getPolicyManager(orgName);
336        this.orgNames.add(policyManager.getOrganizationDN());
337        this.serviceTypeNames.add(serviceTypeName);
338        resourceIndexManager = policyManager.getResourceIndexManager();
339
340        String resultsCacheSessionCapString
341                = SystemProperties.get(RESULTS_CACHE_SESSION_CAP);
342        if (resultsCacheSessionCapString != null) {
343            try {
344                resultsCacheSessionCap
345                        = Integer.parseInt(resultsCacheSessionCapString);
346            } catch (NumberFormatException nfe) {
347                if (PolicyManager.debug.warningEnabled()) {
348                    PolicyManager.debug.warning("PolicyEvaluator:"
349                            + "number format exception: "
350                            + "defaulting resultsCacheSessionCap to "
351                            + DEFAULT_RESULTS_CACHE_SESSION_CAP);
352                }
353                resultsCacheSessionCap = DEFAULT_RESULTS_CACHE_SESSION_CAP;
354            }
355        } else {
356            if (PolicyManager.debug.warningEnabled()) {
357                PolicyManager.debug.warning("PolicyEvaluator:"
358                        + "resultsCacheSessionCap not specified, "
359                        + "defaulting resultsCacheSessionCap to "
360                        + DEFAULT_RESULTS_CACHE_SESSION_CAP);
361            }
362            resultsCacheSessionCap = DEFAULT_RESULTS_CACHE_SESSION_CAP;
363        }
364        if (PolicyManager.debug.messageEnabled()) {
365            PolicyManager.debug.message("PolicyEvaluator:"
366                    + "resultsCacheSessionCap=" + resultsCacheSessionCap);
367        }
368
369        String resultsCacheResourceCapString
370                = SystemProperties.get(RESULTS_CACHE_RESOURCE_CAP);
371        if (resultsCacheResourceCapString != null) {
372            try {
373                resultsCacheResourceCap
374                        = Integer.parseInt(resultsCacheResourceCapString);
375            } catch (NumberFormatException nfe) {
376                if (PolicyManager.debug.warningEnabled()) {
377                    PolicyManager.debug.warning("PolicyEvaluator:"
378                            + "number format exception: "
379                            + "defaulting resultsCacheResourceCap to "
380                            + DEFAULT_RESULTS_CACHE_RESOURCE_CAP);
381                }
382                resultsCacheResourceCap = DEFAULT_RESULTS_CACHE_RESOURCE_CAP;
383            }
384        } else {
385            if (PolicyManager.debug.warningEnabled()) {
386                PolicyManager.debug.warning("PolicyEvaluator:"
387                        + "resultsCacheResourceCap not specified, "
388                        + "defaulting resultsCacheResourceCap to "
389                        + DEFAULT_RESULTS_CACHE_RESOURCE_CAP);
390            }
391            resultsCacheResourceCap = DEFAULT_RESULTS_CACHE_RESOURCE_CAP;
392        }
393        if (PolicyManager.debug.messageEnabled()) {
394            PolicyManager.debug.message("PolicyEvaluator:"
395                    + "resultsCacheResourceCap=" + resultsCacheResourceCap);
396        }
397
398    }
399
400    /**
401     * Creates a new policy evaluator instance.
402     *
403     * @param orgName
404     *         the name of the organization under which the evaluation is being done
405     * @param serviceTypeName
406     *         the name of the <code>ServiceType</code> for which this evaluator can be used
407     * @param applicationName
408     *         the application name containing the policies in question
409     *
410     * @throws PolicyException
411     *         should some error occur constructor the evaluator
412     * @throws SSOException
413     *         should some error occur with regards to any SSO token
414     */
415    public PolicyEvaluator(String orgName, String serviceTypeName, String applicationName)
416            throws PolicyException, SSOException {
417        this(orgName, serviceTypeName);
418        this.applicationName = applicationName;
419
420        registerListener();
421    }
422
423    /**
424     * Register a policy listener for updating policy decision cache if there is none already registered.
425     */
426    private void registerListener() {
427        synchronized (lock) {
428            if (!policyListenerRegistry.containsKey(serviceTypeName)) {
429                listener = new PolicyDecisionCacheListener(serviceTypeName);
430
431                try {
432                    PolicyCache.getInstance().addPolicyListener(listener);
433                } catch (PolicyException pe) {
434                    DEBUG.error("PolicyEvaluator: registering policy decision cache listener failed");
435                }
436
437                policyListenerRegistry.put(serviceTypeName, listener);
438
439                if (DEBUG.messageEnabled()) {
440                    DEBUG.message("PolicyEvaluator:policy listener for service " + serviceTypeName + " added");
441                }
442
443            } else {
444                listener = policyListenerRegistry.get(serviceTypeName);
445            }
446        }
447    }
448
449    /**
450     * Evaluates a simple privilege of boolean type. The privilege indicate
451     * if the user can perform specified action on the specified resource.
452     * Invoking this method would result in <code>PolicyException</code>,
453     * if the syntax for the <code>actionName</code> is not declared to be
454     * boolean, in the service schema.
455     *
456     * @param token single sign on token of the user evaluating policies
457     * @param resourceName name of the resource the user is trying to access
458     * @param actionName name of the action the user is trying to perform on
459     * the resource
460     *
461     * @return the result of the evaluation as a boolean value
462     *
463     * @exception SSOException single-sign-on token invalid or expired
464     * 
465     */
466    public boolean isAllowed(SSOToken token, String resourceName,
467        String actionName) throws PolicyException, SSOException {
468        return (isAllowed(token, resourceName, actionName, 
469                new HashMap()));
470    }
471
472    /**
473     * Evaluates simple privileges of boolean type. The privilege indicate
474     * if the user can perform specified action on the specified resource.
475     * The evaluation depends on user's application environment parameters.
476     * Invoking this method would result in <code>PolicyException</code>,
477     * if the syntax for the <code>actionName</code> is not declared to be
478     * boolean, in the service schema.
479     *
480     * @param token single sign on token of the user evaluating policies
481     * @param resourceName name of the resource the user is trying to access
482     * @param actionName name of the action the user is trying to perform on
483     * the resource
484     * @param envParameters run-time environment parameters
485     *
486     * @return the result of the evaluation as a boolean value
487     *
488     * @throws SSOException single-sign-on token invalid or expired
489     * @throws PolicyException for any other abnormal condition
490     * 
491     * @supported.api
492     */
493    public boolean isAllowed(SSOToken token, String resourceName,
494        String actionName, Map envParameters) throws SSOException,
495        PolicyException {
496        if (PolicyManager.isMigratedToEntitlementService()) {
497            return isAllowedE(token, resourceName, actionName, envParameters);
498        }
499        return isAllowedO(token, resourceName, actionName, envParameters);
500    }
501
502    public boolean isAllowedO(SSOToken token, String resourceName,
503            String actionName, Map envParameters) throws SSOException,
504            PolicyException {
505
506        ActionSchema schema = serviceType.getActionSchema(actionName);
507
508        // Cache the false values for the action names
509        if (booleanActionNameFalseValues == null) {
510            booleanActionNameFalseValues = new HashMap(10);
511        }
512        String falseValue = null;
513        if ((falseValue = (String)
514                booleanActionNameFalseValues.get(actionName)) == null) {
515            falseValue = schema.getFalseValue();
516            // Add it to the cache
517            booleanActionNameFalseValues.put(actionName, falseValue);
518        }
519
520
521        // Cache the true values for the action names
522        if (booleanActionNameTrueValues == null) {
523            booleanActionNameTrueValues = new HashMap(10);
524        }
525
526        String trueValue = null;
527        if ((trueValue = (String)
528                booleanActionNameTrueValues.get(actionName)) == null) {
529            trueValue = schema.getTrueValue();
530            // Add it to the cache
531            booleanActionNameTrueValues.put(actionName, trueValue);
532        }
533
534        if (!AttributeSchema.Syntax.BOOLEAN.equals(schema.getSyntax())) {
535            String objs[] = {actionName};
536            throw new PolicyException(
537                    ResBundleUtils.rbName,
538                    "action_does_not_have_boolean_syntax", objs, null);
539        }
540
541        boolean actionAllowed = false;
542        HashSet actionNames = new HashSet(2);
543        actionNames.add(actionName);
544        PolicyDecision policyDecision = getPolicyDecision(token, resourceName,
545                                   actionNames, envParameters);
546        ActionDecision actionDecision =
547                (ActionDecision) policyDecision.getActionDecisions()
548                .get(actionName);
549
550        if ( actionDecision != null ) {
551            Set set = (Set) actionDecision.getValues();
552            if ( (set != null) ) {
553                if ( set.contains(falseValue) ) {
554                    actionAllowed = false;
555                } else if ( set.contains(trueValue) ) {
556                    actionAllowed = true;
557                }
558            }
559        }
560
561        return actionAllowed;
562    }
563
564    private void padEnvParameters(SSOToken token, String resourceName,
565        String actionName, Map envParameters) throws PolicyException, SSOException {
566        if ((resourceName == null) || (resourceName.trim().length() == 0)) {
567            resourceName = Rule.EMPTY_RESOURCE_NAME;
568        }
569
570        Set originalResourceNames = new HashSet(2);
571        originalResourceNames.add(resourceName);
572
573        String realmName = LDAPUtils.isDN(realm) ?
574            DNMapper.orgNameToRealmName(realm) : realm;
575        try {
576            Application appl = ApplicationManager.getApplication(
577                PolicyConstants.SUPER_ADMIN_SUBJECT,
578                realmName, applicationName);
579            resourceName = appl.getResourceComparator().canonicalize(
580                resourceName);
581        } catch (EntitlementException e) {
582            throw new PolicyException(e);
583        }
584        //Add request resourceName and request actionNames to the envParameters
585        //so that Condition(s)/ResponseProvider(s) can use them if necessary
586        Set resourceNames = new HashSet(2);
587        resourceNames.add(resourceName);
588
589        Set actions = new HashSet();
590        if (actionName != null) {
591            actions.add(actionName);
592        } else {
593            Set actionNames = serviceType.getActionNames();
594            if (actionNames != null) {
595                actions.addAll(actionNames);
596            }
597        }
598
599        envParameters.put(SUN_AM_REQUESTED_RESOURCE, resourceNames);
600        envParameters.put(SUN_AM_ORIGINAL_REQUESTED_RESOURCE,
601                originalResourceNames);
602        envParameters.put(SUN_AM_REQUESTED_ACTIONS, actions);
603        envParameters.put(REALM_DN, asSet(policyManager.getOrganizationDN()));
604
605        // Fix for OPENAM-811
606        String userid = null; 
607        Principal principal = token.getPrincipal();
608        if (principal != null) {
609            userid = principal.getName();
610        }
611        if ((userid != null) && (userid.length() != 0)) {
612           HashSet<String> set = new HashSet<String>();
613           set.add(userid);
614           // Required by the AMIdentityMembershipCondition
615           envParameters.put(Condition.INVOCATOR_PRINCIPAL_UUID, set);
616        } else {
617            if (DEBUG.messageEnabled()) {
618                DEBUG.message("PolicyEvaluator.padEnvParameters() unable to get userid from token.");
619            }
620        }
621    }
622
623    private boolean isAllowedE(SSOToken token, String resourceName,
624        String actionName, Map envParameters) throws SSOException,
625        PolicyException {
626
627        if ((envParameters == null) || envParameters.isEmpty()) {
628            envParameters = new HashMap();
629        }
630
631        padEnvParameters(token, resourceName, actionName, envParameters);
632
633        ActionSchema schema = serviceType.getActionSchema(actionName);
634        
635        if (!AttributeSchema.Syntax.BOOLEAN.equals(schema.getSyntax())) {
636            String objs[] = {actionName};
637            throw new PolicyException(
638                    ResBundleUtils.rbName,
639                    "action_does_not_have_boolean_syntax", objs, null);
640        }
641
642        HashSet actions = new HashSet(2);
643        actions.add(actionName);
644        SSOToken adminSSOToken = (SSOToken) AccessController.doPrivileged(
645            AdminTokenAction.getInstance());
646
647        try {
648            Subject adminSubject =  SubjectUtils.createSubject(token);
649
650            Entitlement entitlement = new Entitlement(serviceTypeName, resourceName, actions);
651            entitlement.canonicalizeResources(adminSubject, realm);
652
653            Evaluator eval = new Evaluator(adminSubject, applicationName);
654            return eval.hasEntitlement(realm, SubjectUtils.createSubject(token), entitlement, envParameters);
655
656        } catch (EntitlementException e) {
657            throw new PolicyException(e);
658        }
659    }
660
661    private String getActionFalseBooleanValue(String actionName)
662        throws InvalidNameException {
663
664        if (serviceType == null) {
665            return Boolean.FALSE.toString();
666        }
667
668        ActionSchema schema = serviceType.getActionSchema(actionName);
669
670        // Cache the false values for the action names
671        if (booleanActionNameFalseValues == null) {
672            booleanActionNameFalseValues = new HashMap(10);
673        }
674        String falseValue = null;
675        if ((falseValue = (String)
676                booleanActionNameFalseValues.get(actionName)) == null) {
677            falseValue = schema.getFalseValue();
678            // Add it to the cache
679            booleanActionNameFalseValues.put(actionName, falseValue);
680        }
681        return falseValue;
682    }
683
684    private String getActionTrueBooleanValue(String actionName)
685        throws InvalidNameException {
686
687        if (serviceType == null) {
688            return Boolean.TRUE.toString();
689        }
690
691        ActionSchema schema = serviceType.getActionSchema(actionName);
692
693        // Cache the true values for the action names
694        if (booleanActionNameTrueValues == null) {
695            booleanActionNameTrueValues = new HashMap(10);
696        }
697
698        String trueValue = null;
699        if ((trueValue = (String)
700            booleanActionNameTrueValues.get(actionName)) == null) {
701            trueValue = schema.getTrueValue();
702            booleanActionNameTrueValues.put(actionName, trueValue);
703        }
704
705        return trueValue;
706    }
707
708    /**
709     * Evaluates privileges of the user to perform the specified actions
710     * on the specified resource.
711     *
712     * @param token single sign on token of the user evaluating policies
713     * @param resourceName name of the resource the user is trying to access
714     * @param actionNames a <code>Set</code> of <code>Sting</code> objects
715     * representing names of the actions the user is trying to perform on
716     * the resource
717     *
718     * @return policy decision
719     *
720     * @exception SSOException single-sign-on token invalid or expired
721     * @exception PolicyException for any other abnormal condition.
722     */
723    public PolicyDecision getPolicyDecision(SSOToken token, String resourceName,
724        Set actionNames) throws PolicyException, SSOException {
725        return getPolicyDecision(token, resourceName, actionNames, null);
726    }
727    
728
729    /**
730     * Evaluates privileges of the user to perform the specified actions
731     * on the specified resource. The evaluation depends on user's
732     * application environment parameters.
733     *
734     * @param token single sign on token of the user evaluating policies
735     * @param resourceName name of the resource the user is trying to access
736     * @param actionNames <code>Set</code> of names(<code>String</code>) of 
737     * the action the user is trying to perform on the resource
738     * @param envParameters <code>Map</code> of run-time environment parameters
739     *
740     * @return policy decision
741     *
742     * @throws SSOException single-sign-on token invalid or expired
743     * @throws PolicyException for any other abnormal condition
744     * 
745     * @supported.api
746     */
747    public PolicyDecision getPolicyDecision(
748            SSOToken token, String resourceName, Set actionNames,
749            Map envParameters)  throws SSOException, PolicyException {
750        if ( (resourceName == null) || (resourceName.length() == 0) ) {
751            resourceName = Rule.EMPTY_RESOURCE_NAME;
752        }
753
754        Set originalResourceNames = new HashSet(2);
755        originalResourceNames.add(resourceName);
756
757        resourceName = serviceType.canonicalize(resourceName);
758
759        //Add request resourceName and request actionNames to the envParameters
760        //so that Condition(s)/ResponseProvider(s) can use them if necessary
761        Set resourceNames = new HashSet(2);
762        resourceNames.add(resourceName);
763
764        /* compute for all action names if passed in actionNames is
765           null or empty */
766        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
767            actionNames = serviceType.getActionNames();
768        }
769
770        Set actions = new HashSet();
771        if (actionNames != null) {
772            actions.addAll(actionNames);
773        }
774
775        /*
776         * We create new HashMap in place of empty map since
777         * Collections.EMPTY_MAP can not be modified
778         */
779        if ((envParameters == null) || envParameters.isEmpty()) {
780            envParameters = new HashMap();
781        }
782
783        envParameters.put(SUN_AM_REQUESTED_RESOURCE, resourceNames);
784        envParameters.put(SUN_AM_ORIGINAL_REQUESTED_RESOURCE, 
785                originalResourceNames);
786        envParameters.put(SUN_AM_REQUESTED_ACTIONS, actions);
787        envParameters.put(REALM_DN, asSet(policyManager.getOrganizationDN()));
788
789        return getPolicyDecision(token, resourceName, actionNames,
790                envParameters, new HashSet());
791    }
792
793    /**
794     * Evaluates privileges of the user to perform the specified actions
795     * on the specified resource. The evaluation depends on user's
796     * application environment parameters.
797     *
798     * @param token single sign on token of the user evaluating policies
799     * @param resourceName name of the resource the user is trying to access
800     * @param actionNames <code>Set</code> of names(<code>String</code>) of the
801     * action the user is trying to perform on the resource.
802     * @param envParameters run-time environment parameters
803     * @param visitedOrgs names of organizations that have been already visited
804     *                    during policy evaluation for this request
805     *
806     * @return policy decision
807     *
808     * @exception SSOException single-sign-on token invalid or expired
809     * @exception PolicyException if any policy evaluation error.
810     */
811    private PolicyDecision getPolicyDecision(
812        SSOToken token, String resourceName, Set actionNames,
813        Map envParameters, Set visitedOrgs)
814        throws PolicyException, SSOException {
815        if (MonitoringUtil.isRunning()) {
816            SsoServerPolicySvcImpl sspsi =
817                Agent.getPolicySvcMBean();
818            sspsi.incPolicyEvalsIn();
819        }
820
821        try {
822            return (PolicyManager.isMigratedToEntitlementService()) ? 
823                getPolicyDecisionE(token, resourceName, actionNames,
824                envParameters) : getPolicyDecisionO(token, resourceName,
825                actionNames,
826                envParameters, visitedOrgs);
827        } finally {
828            if (MonitoringUtil.isRunning()) {
829                SsoServerPolicySvcImpl sspsi =
830                        Agent.getPolicySvcMBean();
831                sspsi.incPolicyEvalsOut();
832            }
833        }
834    }
835
836
837    /**
838     * Evaluates privileges of the user to perform the specified actions
839     * on the specified resource. The evaluation depends on user's
840     * application environment parameters.
841     *
842     * @param token single sign on token of the user evaluating policies
843     * @param resourceName name of the resource the user is trying to access
844     * @param actionNames <code>Set</code> of names(<code>String</code>) of the
845     * action the user is trying to perform on the resource.
846     * @param envParameters run-time environment parameters
847     * @return policy decision
848     *
849     * @exception SSOException single-sign-on token invalid or expired
850     * @exception PolicyException if any policy evaluation error.
851     */
852    private PolicyDecision getPolicyDecisionE(
853        SSOToken token, String resourceName, Set actionNames,
854        Map envParameters)
855        throws PolicyException, SSOException {
856
857        if ( DEBUG.messageEnabled() ) {
858            DEBUG.message("Evaluating policies at org " + orgName);
859        }
860
861        /* compute for all action names if passed in actionNames is
862           null or empty */
863        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
864            actionNames = serviceType.getActionNames();
865        }
866
867        SSOToken adminSSOToken = (SSOToken) AccessController.doPrivileged(
868            AdminTokenAction.getInstance());
869
870        try {
871            Evaluator eval = new Evaluator(
872                SubjectUtils.createSubject(adminSSOToken), applicationName);
873            Subject sbj = (token != null) ? SubjectUtils.createSubject(token) :
874                null;
875            List<Entitlement> entitlements = eval.evaluate(
876                orgName, sbj, resourceName, envParameters, false);
877            if ((entitlements != null) && !entitlements.isEmpty()) {
878                Entitlement e = entitlements.iterator().next();
879                return (entitlementToPolicyDecision(e, actionNames));
880            }
881        } catch (EntitlementException e) {
882            throw new PolicyException(e);
883        }
884        return (new PolicyDecision());
885    }
886
887    private PolicyDecision getPolicyDecisionO(
888            SSOToken token, String resourceName, Set actionNames,
889            Map envParameters, Set visitedOrgs)
890            throws PolicyException, SSOException {
891
892        if ( DEBUG.messageEnabled() ) {
893            DEBUG.message("Evaluating policies at org " + orgName);
894        }
895
896        /* compute for all action names if passed in actionNames is
897           null or empty */
898        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
899            actionNames = serviceType.getActionNames();
900        }
901
902        Set actions = new HashSet();
903        actions.addAll(actionNames);
904
905        PolicyDecision mergedPolicyDecision = null;
906        Set policyNameSet = null;
907        Set toRemovePolicyNameSet = null;
908        policyNameSet = resourceIndexManager.getPolicyNames(
909                serviceType, resourceName, INCLUDE_SUPER_RESOURCE_POLCIES);
910        if ( DEBUG.messageEnabled() ) {
911            String tokenPrincipal =
912                    (token != null) ? token.getPrincipal().getName()
913                    : PolicyUtils.EMPTY_STRING;
914            DEBUG.message(new StringBuffer("at PolicyEvaluator")
915                .append(".getPolicyDecision()")
916                .append(" principal, resource name, ")
917                .append("action names, policy names,")
918                .append(" orgName =")
919                .append(tokenPrincipal) .append(",  ")
920                .append(resourceName) .append(",  ")
921                .append(actionNames) .append(",  ")
922                .append(policyNameSet).append(",  ")
923                .append(orgName).toString());
924        }
925        Iterator policyIter = policyNameSet.iterator();
926        while ( policyIter.hasNext() ) {
927            String policyName = (String) policyIter.next();
928            Policy policy = policyManager.getPolicy(policyName,
929                USE_POLICY_CACHE);
930            if ( policy != null && policy.isActive()) {
931                //policy might have been removed or inactivated
932                PolicyDecision policyDecision = policy.getPolicyDecision(token,
933                       serviceTypeName, resourceName, actions, envParameters);
934                if (!policy.isReferralPolicy() && policyDecision.hasAdvices()) {
935                    addAdvice(policyDecision, ADVICING_ORGANIZATION, orgName);
936                }
937
938                // Let us log all policy evaluation results
939                if (PolicyUtils.logStatus && (token != null)) {
940                    String decision = policyDecision.toString();
941                    if (decision != null && decision.length() != 0) {
942                        String[] objs = { policyName, orgName, serviceTypeName,
943                                        resourceName, actionNames.toString(),
944                                        decision };
945                            PolicyUtils.logAccessMessage("POLICY_EVALUATION",
946                                                objs, token, serviceTypeName);
947                    }
948                }
949                if ( mergedPolicyDecision == null ) {
950                    mergedPolicyDecision = policyDecision;
951                } else {
952                    mergePolicyDecisions(serviceType, policyDecision,
953                           mergedPolicyDecision);
954                }
955
956                if (!PolicyConfig.continueEvaluationOnDenyDecision()) {
957                    actions.removeAll(getFinalizedActions(serviceType,
958                            mergedPolicyDecision));
959                }
960
961                if ( actions.isEmpty() ) {
962                    break;
963                }
964            } else { // add policy names to toRemovePolicyNameSet
965                if (toRemovePolicyNameSet == null) {
966                    toRemovePolicyNameSet = new HashSet();
967                }
968                toRemovePolicyNameSet.add(policyName);
969                if ( DEBUG.messageEnabled() ) {
970                    DEBUG.message("PolicyEvaluator.getPolicyDecision():"
971                        +policyName+ " is inactive or non-existent");
972                }
973            }
974        }
975
976        // remove inactive/missing policies from policyNameSet
977        if (toRemovePolicyNameSet != null) {
978            policyNameSet.removeAll(toRemovePolicyNameSet);
979        }
980
981        Set orgsToVisit = getOrgsToVisit(policyNameSet);
982
983        if (PolicyConfig.orgAliasMappedResourcesEnabled()
984                    && PolicyManager.WEB_AGENT_SERVICE.equalsIgnoreCase(
985                    serviceTypeName)) {
986            String orgAlias = policyManager.getOrgAliasWithResource(
987                    resourceName);
988            if (orgAlias != null) {
989                String orgWithAlias = policyManager.getOrgNameWithAlias(
990                        orgAlias);
991                if (orgWithAlias != null) {
992                    if ( DEBUG.messageEnabled() ) {
993                        DEBUG.message("PolicyEvaluator.getPolicyDecision():"
994                                + "adding orgWithAlias to orgsToVisit="
995                                + orgWithAlias);
996                    }
997                    orgsToVisit.add(orgWithAlias);
998                }
999            }
1000        }
1001
1002        if ( DEBUG.messageEnabled() ) {
1003            DEBUG.message(new StringBuffer("at PolicyEvaluator")
1004                .append(".getPolicyDecision()")
1005                .append(" orgsToVist=").append(orgsToVisit.toString())
1006                .toString());
1007        }
1008        orgsToVisit.removeAll(visitedOrgs);
1009        if ( DEBUG.messageEnabled() ) {
1010            DEBUG.message(new StringBuffer("at PolicyEvaluator")
1011                .append(".getPolicyDecision()")
1012                .append(" orgsToVist(after removing already visited orgs=")
1013                .append(orgsToVisit.toString())
1014                .toString() );
1015        }
1016        while ( !orgsToVisit.isEmpty() && !actions.isEmpty() ) {
1017            String orgToVisit = (String) orgsToVisit.iterator().next();
1018            orgsToVisit.remove(orgToVisit);
1019            visitedOrgs.add(orgToVisit);
1020            try {
1021                // need to use admin sso token here. Need all privileges to
1022                // check for the organzation
1023                policyManager.verifyOrgName(orgToVisit);
1024            } catch (NameNotFoundException nnfe) {
1025                if( DEBUG.warningEnabled()) {
1026                    DEBUG.warning("Organization does not exist - "
1027                            + "skipping referral to " + orgToVisit);
1028                }
1029                continue;
1030            }
1031            PolicyEvaluator pe = new PolicyEvaluator(orgToVisit,
1032                    serviceTypeName);
1033            /**
1034             * save current realm DN before passing control down to sub-realm
1035             */
1036            Set<String> savedRealmDn = (Set<String>) envParameters.get(REALM_DN);
1037            // Update env to point to the realm policy config data.
1038            envParameters.put(REALM_DN, asSet(DNMapper.orgNameToDN(orgToVisit)));
1039            PolicyDecision policyDecision
1040                    = pe.getPolicyDecision(token, resourceName, actionNames,
1041                    envParameters,visitedOrgs);
1042            // restore back the policy config data for the parent realm
1043            envParameters.put(REALM_DN, savedRealmDn);
1044            if ( mergedPolicyDecision == null ) {
1045                mergedPolicyDecision = policyDecision;
1046            } else {
1047                mergePolicyDecisions(serviceType, policyDecision,
1048                       mergedPolicyDecision);
1049            }
1050            if (!PolicyConfig.continueEvaluationOnDenyDecision()) {
1051                actions.removeAll(getFinalizedActions(serviceType,
1052                        mergedPolicyDecision));
1053            }
1054        }
1055
1056        if ( mergedPolicyDecision == null ) {
1057            mergedPolicyDecision = new PolicyDecision();
1058        }
1059
1060        return mergedPolicyDecision;
1061    }
1062
1063    /**
1064     * Gets protected resources for a user identified by single sign on token
1065     * Conditions defined  in the policies are ignored while 
1066     * computing protected resources. 
1067     * Only resources that are sub resources of the  given 
1068     * <code>rootResource</code> or equal to the given <code>rootResource</code>
1069     * would be returned. 
1070     * If all policies applicable to a resource are 
1071     * only referral policies, no <code>ProtectedResource</code> would be
1072     * returned for such a resource.
1073     *
1074     * @param token single sign on token of the user
1075     * @param rootResource  only resources that are sub resources of the  
1076     *                      given <code>rootResource</code> or equal to the
1077     *                      given <code>rootResource</code> would be returned
1078     *                      <code>rootResource</code> would be returned.
1079     *                      If <code>PolicyEvaluator.ALL_RESOURCES</code> is 
1080     *                      passed as <code>rootResource</code>, resources under
1081     *                      all root  resources of the service 
1082     *                      type are considered while computing protected 
1083     *                      resources.
1084     * @return <code>Set</code> of protected resources. The set 
1085     *         contains <code>ProtectedResource</code> objects. 
1086     *
1087     * @throws SSOException if single sign on token is invalid
1088     * @throws PolicyException for any other abnormal condition
1089     * @see ProtectedResource
1090     *
1091     * @supported.api
1092     *
1093     */
1094    public Set getProtectedResourcesIgnoreConditions(
1095        SSOToken token, String rootResource)  
1096        throws SSOException, PolicyException 
1097    {
1098        if ( (rootResource == null) || (rootResource.equals("")) ) {
1099            rootResource = EMPTY_RESOURCE_NAME;
1100        }
1101        Set protectedResources = new HashSet();
1102        Set topLevelResources = null;
1103        if (rootResource.equals(ALL_RESOURCES)) {
1104            topLevelResources 
1105                    = resourceIndexManager.getTopLevelResourceNames(
1106                    serviceType);
1107        } else {
1108            topLevelResources = new HashSet();
1109            topLevelResources.add(rootResource);
1110        }
1111        Iterator iter = topLevelResources.iterator();
1112        while (iter.hasNext()) {
1113            String topLevelResource = (String)iter.next();
1114            Set resourceNames 
1115                    = getResourceNames(token, topLevelResource, true);
1116            Iterator resourceIter = resourceNames.iterator();
1117            while (resourceIter.hasNext()) {
1118                String resourceName = (String)resourceIter.next();
1119                Set protectingPolicies 
1120                        = getProtectingPolicies(token, resourceName);
1121                if ((protectingPolicies != null) 
1122                            && (!protectingPolicies.isEmpty())) {
1123                    boolean allReferralPolicies = true;
1124                    Iterator iter1 = protectingPolicies.iterator();
1125                    while (iter1.hasNext()){
1126                        Policy policy = (Policy)iter1.next();
1127                        if (!policy.isReferralPolicy()) {
1128                            allReferralPolicies = false;
1129                            break;
1130                        }
1131                    }
1132                    if (!allReferralPolicies) {
1133                        protectedResources.add(
1134                                new ProtectedResource(resourceName, 
1135                                protectingPolicies));
1136                    }
1137                }
1138            }
1139        }
1140        return protectedResources;
1141    }
1142
1143    /**
1144     * Gets policies applicable to user that are  protecting 
1145     * the specified resource.
1146     *
1147     * @param token single sign on token of the user evaluating policies
1148     * @param resourceName name of the resource the user is trying to access
1149     *
1150     * @return set of policies applicable to user that are protecting the 
1151     *         specified resource
1152     *
1153     * @throws PolicyException policy exception coming from policy framework
1154     * @throws SSOException single-sign-on token invalid or expired
1155     * 
1156     */
1157    Set getProtectingPolicies(
1158        SSOToken token, String resourceName)  
1159        throws PolicyException, SSOException 
1160    {
1161        return getProtectingPolicies(token, resourceName, new HashSet());
1162    }
1163
1164    /**
1165     * Gets policies applicable to user that are  protecting 
1166     * the specified resource.
1167     *
1168     * @param token single sign on token of the user evaluating policies
1169     * @param resourceName name of the resource the user is trying to access
1170     *
1171     * @param visitedOrgs names of organizations that have been 
1172     *            already visited during evaluation for this request
1173     * @return set of policies applicable to user that are protecting the 
1174     *         specified resource
1175     *
1176     * @throws PolicyException policy exception coming from policy framework
1177     * @throws SSOException single-sign-on token invalid or expired
1178     * 
1179     */
1180    private Set getProtectingPolicies(
1181        SSOToken token, String resourceName, Set visitedOrgs)  
1182        throws PolicyException, SSOException 
1183    {
1184
1185        Set protectingPolicies = new HashSet();
1186
1187
1188        // false - do not include super resource policies
1189        // includes EXACT_MATCH and WILD_CARD_MATCH
1190        Set policyNameSet = resourceIndexManager.getPolicyNames(
1191                serviceType, resourceName, false);
1192        Set toRemovePolicyNameSet = null;
1193        if ( DEBUG.messageEnabled() ) {
1194            String tokenPrincipal = 
1195                    (token != null) ? token.getPrincipal().getName()
1196                    : PolicyUtils.EMPTY_STRING;
1197            DEBUG.message(new StringBuffer(
1198                    "at PolicyEvaluator.getProtectingPolicies()")
1199                .append(" principal, resource name, policy names,")
1200                .append(" orgName =")
1201                .append(tokenPrincipal) .append(",  ")
1202                .append(resourceName) .append(",  ")
1203                .append(policyNameSet).append(",  ")
1204                .append(orgName).toString());
1205        }
1206        Iterator policyIter = policyNameSet.iterator();
1207        while ( policyIter.hasNext() ) {
1208            String policyName = (String) policyIter.next();
1209            Policy policy = policyManager.getPolicy(policyName);
1210            if ( policy != null && policy.isActive()) { 
1211                //policy might have been removed or inactivated
1212                if (!policy.isReferralPolicy()) {
1213                    if (policy.isApplicableToUser(token)) {
1214                        policy.setOrganizationName(orgName);
1215                        protectingPolicies.add(policy); 
1216                    }
1217                } else {
1218                    policy.setOrganizationName(orgName);
1219                    protectingPolicies.add(policy);
1220                }
1221            } else { // add policy names to toRemovePolicyNameSet
1222                if (toRemovePolicyNameSet == null) {
1223                    toRemovePolicyNameSet = new HashSet();
1224                }
1225                toRemovePolicyNameSet.add(policyName);
1226                if ( DEBUG.messageEnabled() ) {
1227                    DEBUG.message("PolicyEvaluator.getProtectingPolicies():"
1228                        +policyName+ " is inactive or non-existent");
1229                }
1230            }
1231        }
1232
1233        // remove inactive/missing policies from policyNameSet
1234        if (toRemovePolicyNameSet != null) {
1235            policyNameSet.removeAll(toRemovePolicyNameSet);
1236        }
1237
1238        //include super resource policies provided they are referral policies
1239        policyNameSet = resourceIndexManager.getSuperResourcePolicyNames(
1240                serviceType, resourceName);
1241        if (toRemovePolicyNameSet != null) {
1242            toRemovePolicyNameSet.clear();
1243        }
1244        policyIter = policyNameSet.iterator();
1245        while ( policyIter.hasNext() ) {
1246            String policyName = (String) policyIter.next();
1247            Policy policy = policyManager.getPolicy(policyName);
1248            if ( policy != null && policy.isActive()) { 
1249                //policy might have been removed or inactivated
1250                if (policy.isReferralPolicy()) {
1251                        policy.setOrganizationName(orgName);
1252                        protectingPolicies.add(policy);
1253                }
1254            } else { // add policy names to toRemovePolicyNameSet
1255                if (toRemovePolicyNameSet == null) {
1256                    toRemovePolicyNameSet = new HashSet();
1257                }
1258                toRemovePolicyNameSet.add(policyName);
1259                if ( DEBUG.messageEnabled() ) {
1260                    DEBUG.message("PolicyEvaluator.getProtectingPolicies():"
1261                        +policyName+ " is inactive or non-existent");
1262                }
1263            }
1264        }
1265        // remove inactive/missing policies from policyNameSet
1266        if (toRemovePolicyNameSet != null) {
1267            policyNameSet.removeAll(toRemovePolicyNameSet);
1268        }
1269
1270        Set orgsToVisit = getOrgsToVisit(policyNameSet);
1271        if ( DEBUG.messageEnabled() ) {
1272            DEBUG.message(new StringBuffer(
1273                    "at PolicyEvaluator.getProtectingPolicies()")
1274                .append(" orgsToVist=").append(orgsToVisit.toString())
1275                .toString());
1276        }
1277
1278        if (PolicyConfig.orgAliasMappedResourcesEnabled()
1279                    && PolicyManager.WEB_AGENT_SERVICE.equalsIgnoreCase(
1280                    serviceTypeName)) {
1281            String orgAlias = policyManager.getOrgAliasWithResource(
1282                    resourceName); 
1283            if (orgAlias != null) {
1284                String orgWithAlias = policyManager.getOrgNameWithAlias(
1285                        orgAlias);
1286                if (orgWithAlias != null) {
1287                    if ( DEBUG.messageEnabled() ) {
1288                        DEBUG.message("PolicyEvaluator.getProtectingPolicies():"
1289                                + "adding orgWithAlias to orgsToVisit="
1290                                + orgWithAlias);
1291                    }
1292                    orgsToVisit.add(orgWithAlias);
1293                }
1294            }
1295        }
1296
1297        orgsToVisit.removeAll(visitedOrgs);
1298        if ( DEBUG.messageEnabled() ) {
1299            DEBUG.message(new StringBuffer(
1300                    "at PolicyEvaluator.getProtectingPolicies()")
1301                .append(" orgsToVist(after removing already visited orgs=")
1302                .append(orgsToVisit.toString())
1303                .toString() );
1304        }
1305        while (!orgsToVisit.isEmpty() ) {
1306            String orgToVisit = (String) orgsToVisit.iterator().next();
1307            orgsToVisit.remove(orgToVisit);
1308            visitedOrgs.add(orgToVisit);
1309            try {
1310                // need to use admin sso token here. Need all privileges to
1311                // check for the organzation
1312                policyManager.verifyOrgName(orgToVisit);
1313            } catch (NameNotFoundException nnfe) {
1314                if( DEBUG.warningEnabled()) {
1315                    DEBUG.warning("Organization does not exist - "
1316                            + "skipping referral to " + orgToVisit);
1317                }
1318                continue;
1319            }
1320            PolicyEvaluator pe 
1321                    = new PolicyEvaluator(orgToVisit, serviceTypeName);
1322            Set pp = pe.getProtectingPolicies(token, resourceName,
1323                    visitedOrgs); 
1324            protectingPolicies.addAll(pp);
1325        }
1326
1327        String principalName =  (token != null) 
1328                ? token.getPrincipal().getName()
1329                : PolicyUtils.EMPTY_STRING;
1330
1331        StringBuffer sb = null;
1332        String pp = null;
1333        if (PolicyManager.debug.messageEnabled() || PolicyUtils.logStatus) {
1334            sb = new StringBuffer();
1335            Iterator pIter = protectingPolicies.iterator();
1336            while (pIter.hasNext()) {
1337                Policy policy = (Policy)pIter.next();
1338                sb.append(policy.getOrganizationName()).append(":")
1339                        .append(policy.getName()) .append(",");
1340            }
1341            pp = sb.toString();
1342        }
1343
1344
1345        if (PolicyManager.debug.messageEnabled()) {
1346            PolicyManager.debug.message("Computed policies "
1347                    + " protecting resource "
1348                    + resourceName
1349                    + "for principal:" + principalName + " " + pp);
1350        }
1351
1352        if (PolicyUtils.logStatus && (token != null)) {
1353            String[] objs = { principalName, 
1354                    resourceName, pp };
1355            PolicyUtils.logAccessMessage("PROTECTED_RESOURCES", objs, token,
1356                    serviceTypeName);
1357        }
1358        return protectingPolicies;
1359    }
1360
1361    /**
1362     * Gets resource result objects given a resource name. The set
1363     * contains <code>ResourceResult</code> objects for all resources 
1364     * that would affect policy decisions for any resource associated with the 
1365     * argument resource name. To determine whether to include the
1366     * <code>ResourceResult</code> of a resource,  we compare argument resource
1367     * name and policy resource name, treating wild characters in the policy 
1368     * resource name as wild. If the comparison resulted in
1369     * <code>EXACT_MATCH</code>, <code>WILD_CARD_MACTH</code> or
1370     * <code>SUB_RESOURCE_MACTH</code>, the resource result would be
1371     * included.
1372     *
1373     * @param token single sign on token of the user evaluating policies
1374     * @param resourceName name of the resource 
1375     * @param scope indicates whether to compute the resource result based on
1376     *              the policy decision for only the <code>resourceName</code>
1377     *              or all the resources associated with the resource name.
1378     *              The valid scope values are:
1379     *              <ul>
1380     *              <li><code>ResourceResult.SUBTREE_SCOPE</code>
1381     *              <li><code>ResourceResult.STRICT_SUBTREE_SCOPE</code>
1382     *              <li><code>ResourceResult.SELF_SCOPE</code>
1383     *              <ul>
1384     *              If the scope is <code>ResourceResult.SUBTREE_SCOPE</code>,
1385     *              the method will return a set of <code>ResourceResult</code>
1386     *              objects, one of them for the <code>resourceName</code> and
1387     *              its sub resources; the others are for resources that match
1388     *              the <code>resourceName</code> by wildcard. If the scope is
1389     *              <code>ResourceResult.STRICT_SUBTREE_SCOPE</code>, the 
1390     *              method will return a set object that contains one 
1391     *              <code>ResourceResult</code> object. The
1392     *              <code>ResourceResult</code> contains the policy decisions
1393     *              regarding the <code>resourceName</code> and its sub
1394     *              resources. If the scope is
1395     *              <code>ResourceResult.SELF_SCOPE</code>, the method will
1396     *              return a set object that contains one
1397     *              <code>ResourceResult</code> object.
1398     *              The <code>ResourceResult</code> contains the policy decision
1399     *              regarding the <code>resourceName</code> only.
1400     *
1401     * @param envParameters run-time environment parameters
1402     *
1403     * @return set of <code>ResourceResult</code> objects
1404     *
1405     * @throws SSOException if <code>token</code> is invalid
1406     * @throws PolicyException for any other abnormal condition
1407     *
1408     * @see ResourceMatch#EXACT_MATCH
1409     * @see ResourceMatch#SUB_RESOURCE_MATCH
1410     * @see ResourceMatch#WILDCARD_MATCH
1411     * @see ResourceResult#SUBTREE_SCOPE
1412     * @see ResourceResult#STRICT_SUBTREE_SCOPE
1413     * @see ResourceResult#SELF_SCOPE
1414     *
1415     * 
1416     * @supported.api
1417     */
1418    public Set getResourceResults(SSOToken token, 
1419            String resourceName, String scope, Map envParameters) 
1420            throws SSOException, PolicyException {
1421        return (PolicyManager.isMigratedToEntitlementService()) ?
1422            getResourceResultsE(token, resourceName, scope, envParameters) :
1423            getResourceResultsO(token, resourceName, scope, envParameters);
1424    }
1425    
1426    private Set getResourceResultsO(SSOToken token,
1427            String resourceName, String scope, Map envParameters)
1428            throws SSOException, PolicyException {
1429        Set resultsSet;
1430
1431        if (ResourceResult.SUBTREE_SCOPE.equals(scope)) {
1432            resultsSet = getResourceResultTree(token, resourceName, scope,
1433                                         envParameters).getResourceResults();
1434        } else if (ResourceResult.STRICT_SUBTREE_SCOPE.equals(scope)
1435                   || ResourceResult.SELF_SCOPE.equals(scope)) {
1436            ResourceResult result = getResourceResultTree(token, resourceName,
1437                                         scope, envParameters);
1438            resultsSet = new HashSet();
1439            resultsSet.add(result);
1440        } else {
1441            DEBUG.error("PolicyEvaluator: invalid request scope: " + scope);
1442            String objs[] = {scope};
1443            throw new PolicyException(ResBundleUtils.rbName,
1444                "invalid_request_scope", objs, null);
1445        }
1446
1447        return resultsSet;
1448    }
1449
1450    private Set getResourceResultsE(SSOToken token,
1451            String resourceName, String scope, Map envParameters)
1452            throws SSOException, PolicyException {
1453
1454        if ((envParameters == null) || envParameters.isEmpty()) {
1455            envParameters = new HashMap();
1456        }
1457        padEnvParameters(token, resourceName, null, envParameters);
1458
1459        Set resultsSet;
1460        boolean subTreeSearch = false;
1461
1462        if (ResourceResult.SUBTREE_SCOPE.equals(scope)) {
1463            subTreeSearch = true;
1464            //resultsSet = getResourceResultTree(token, resourceName, scope,
1465            //                            envParameters).getResourceResults();
1466        } else if (ResourceResult.STRICT_SUBTREE_SCOPE.equals(scope)
1467                   || ResourceResult.SELF_SCOPE.equals(scope)) {
1468            /*
1469            ResourceResult result = getResourceResultTree(token, resourceName,
1470                                         scope, envParameters);
1471            resultsSet = new HashSet();
1472            resultsSet.add(result);*/
1473        } else {
1474            DEBUG.error("PolicyEvaluator: invalid request scope: " + scope);
1475            String objs[] = {scope};
1476            throw new PolicyException(ResBundleUtils.rbName,
1477                "invalid_request_scope", objs, null);
1478        }
1479
1480        SSOToken adminSSOToken = (SSOToken)AccessController.doPrivileged(
1481            AdminTokenAction.getInstance());
1482
1483        try {
1484            // Parse the resource name before proceeding.
1485            resourceName = serviceType.canonicalize(resourceName);
1486
1487            Subject userSubject = SubjectUtils.createSubject(token);
1488            Evaluator eval = new Evaluator(
1489                SubjectUtils.createSubject(adminSSOToken), applicationName);
1490
1491            List<Entitlement> entitlements = eval.evaluate(
1492                realm, userSubject, resourceName,
1493                envParameters, subTreeSearch);
1494            resultsSet = new HashSet();
1495
1496            if (!entitlements.isEmpty()) {
1497                if (!subTreeSearch) {
1498                    resultsSet.add(entitlementToResourceResult(
1499                        (Entitlement)entitlements.iterator().next()));
1500                } else {
1501                    ResourceResult virtualResourceResult =
1502                        new ResourceResult(ResourceResult.VIRTUAL_ROOT,
1503                            new PolicyDecision());
1504                    for (Entitlement ent : entitlements ) {
1505                        ResourceResult r = entitlementToResourceResult(ent);
1506                        virtualResourceResult.addResourceResult(r, serviceType);
1507                    }
1508
1509                    resultsSet.addAll(
1510                        virtualResourceResult.getResourceResults());
1511                }
1512            }
1513        } catch (Exception e) {
1514            DEBUG.error("Error in getResourceResults", e);
1515            throw new PolicyException(e.getMessage()); //TOFIX
1516        }
1517
1518        return resultsSet;
1519    }
1520
1521   
1522    private ResourceResult entitlementToResourceResult(
1523        Entitlement entitlement
1524    ) throws PolicyException {
1525        return new ResourceResult(entitlement.getRequestedResourceName(),
1526            entitlementToPolicyDecision(entitlement, Collections.EMPTY_SET));
1527    }
1528    
1529    private PolicyDecision entitlementToPolicyDecision(
1530        Entitlement entitlement,
1531        Set<String> actionNames
1532    ) throws PolicyException {
1533        PolicyDecision pd = new PolicyDecision();
1534        Map actionValues = entitlement.getActionValues();
1535
1536        if ((actionValues != null) && !actionValues.isEmpty()) {
1537            for (Iterator i = actionValues.keySet().iterator(); i.hasNext();) {
1538                String actionName = (String) i.next();
1539                Set set = new HashSet();
1540                boolean isBooleanAction = true;
1541                if (serviceType != null) {
1542                    ActionSchema as = null;
1543                    try {
1544                        as = serviceType.getActionSchema(actionName);
1545                    } catch (InvalidNameException inex) {
1546                        if (DEBUG.warningEnabled()) {
1547                            DEBUG.warning("PolicyEvaluator." +
1548                                "entitlementToPolicyDecision:", inex);
1549                        }
1550                    }
1551                    isBooleanAction = (as != null) &&
1552                        as.getSyntax().equals(AttributeSchema.Syntax.BOOLEAN);
1553                }
1554
1555                if (isBooleanAction) {
1556
1557                    Boolean values = (Boolean) actionValues.get(actionName);
1558
1559                    if (values.booleanValue()) {
1560                        set.add(getActionTrueBooleanValue(actionName));
1561                    } else {
1562                        set.add(getActionFalseBooleanValue(actionName));
1563                    }
1564                } else {
1565                    // Parse the action name to get the value
1566                    int index = actionName.indexOf('_');
1567                    if (index != -1) {
1568                        set.add(actionName.substring(index+1));
1569                        actionName = actionName.substring(0, index);
1570                    } else {
1571                        set.add(actionName);
1572                    }
1573                }
1574
1575                ActionDecision ad = new ActionDecision(actionName, set);
1576                ad.setAdvices(entitlement.getAdvices());
1577                ad.setTimeToLive(entitlement.getTTL());
1578                pd.addActionDecision(ad, serviceType);
1579            }
1580        } else {
1581            Map advices = entitlement.getAdvices();
1582            if ((advices != null) && (!advices.isEmpty()) &&
1583                ((actionNames == null) || actionNames.isEmpty())) {
1584                actionNames = serviceType.getActionNames();
1585            }
1586            for (String actionName : actionNames) {
1587                Set set = new HashSet();
1588                // Determinte if the serviceType have boolean action values
1589                ActionSchema as = null;
1590                if (serviceType != null) {
1591                    try {
1592                        as = serviceType.getActionSchema(actionName);
1593                    } catch (InvalidNameException inex) {
1594                        if (DEBUG.warningEnabled()) {
1595                            DEBUG.warning("PolicyEvaluator." +
1596                                "entitlementToPolicyDecision:", inex);
1597                        }
1598                    }
1599                }
1600                if ((as == null) ||
1601                    as.getSyntax().equals(AttributeSchema.Syntax.BOOLEAN)) {
1602                    set.add(getActionFalseBooleanValue(actionName));
1603                } else {
1604                    set.addAll(as.getDefaultValues());
1605                }
1606                ActionDecision ad = new ActionDecision(actionName, set);
1607                ad.setAdvices(entitlement.getAdvices());
1608                ad.setTimeToLive(entitlement.getTTL());
1609                pd.addActionDecision(ad, serviceType);
1610            }
1611        }
1612
1613        pd.setTimeToLive(entitlement.getTTL());
1614        pd.setResponseAttributes(entitlement.getAttributes());
1615        return pd;
1616    }
1617
1618    /**
1619     * Gets resource result given a resource name. <code>ResourceResult</code>
1620     * is a tree representation of policy decisions for all resources rooted 
1621     * at the resource name.
1622     * To determine whether a resource defined in the policy
1623     * is a sub resource of argument resource name, argument resource name 
1624     * and policy resource name are compared, treating wild characters as 
1625     * literals. If comparison resulted in <code>EXACT_MACTH</code> or
1626     * <code>SUB_RESOURCE_MACTH</code>, the resource would be included
1627     *
1628     * @param token single sign on token of the user evaluating policies
1629     * @param resourceName name of the resource 
1630     * @param scope indicates whether to compute the resource result based on
1631     *              the policy decision for only the <code>resourceName</code>
1632     *              or all the resources associated with the resource name.
1633     *              The valid scope values are:
1634     *              <ul>
1635     *              <li><code>ResourceResult.SUBTREE_SCOPE</code>
1636     *              <li><code>ResourceResult.STRICT_SUBTREE_SCOPE</code>
1637     *              <li><code>ResourceResult.SELF_SCOPE</code>
1638     *              </ul>
1639     *              If the scope is <code>ResourceResult.SUBTREE_SCOPE</code> or
1640     *              <code>ResourceResult.STRICT_SUBTREE_SCOPE</code>, the method
1641     *              will return a <code>ResourceResult</code> object that
1642     *              contains the policy decisions regarding the
1643     *              <code>resourceName</code> and its sub resources.
1644     *              If the scope is <code>ResourceResult.SELF_SCOPE</code>, the
1645     *              method will return a <code>ResourceResult</code> object that
1646     *              contains the policy decision regarding the
1647     *              <code>resourceName</code> only. Note, scope values
1648     *              <code>ResourceResult.SUBTREE_SCOPE</code> and
1649     *              <code>ResourceResult.STRICT_SUBTREE_SCOPE</code> are being
1650     *              treated as the same for backword compatibility reasons. This
1651     *              method is being deprecated. The method
1652     *              <code>getResourceResults()</code> should be used instead. 
1653     *
1654     * @param envParameters run-time environment parameters
1655     *
1656     * @return <code>ResourceResult</code>.
1657     *
1658     * @throws SSOException if <code>token</code> is invalid 
1659     * @throws PolicyException for any other abnormal condition
1660     *
1661     * @see ResourceMatch#EXACT_MATCH
1662     * @see ResourceMatch#SUB_RESOURCE_MATCH
1663     * @see ResourceMatch#WILDCARD_MATCH
1664     * @see ResourceResult#SUBTREE_SCOPE
1665     * @see ResourceResult#STRICT_SUBTREE_SCOPE
1666     * @see ResourceResult#SELF_SCOPE
1667     *
1668     * @deprecated Use <code>getResourceResults()</code>
1669     *
1670     * @supported.api
1671     *
1672     */
1673    public ResourceResult getResourceResult(SSOToken token, 
1674            String resourceName, String scope, Map envParameters) 
1675            throws SSOException, PolicyException {
1676        if (ResourceResult.SUBTREE_SCOPE.equals(scope)
1677                || ResourceResult.STRICT_SUBTREE_SCOPE.equals(scope) 
1678                || ResourceResult.SELF_SCOPE.equals(scope)) {
1679            if (ResourceResult.SUBTREE_SCOPE.equals(scope)) {
1680                scope = ResourceResult.STRICT_SUBTREE_SCOPE; 
1681            }
1682            return getResourceResultTree(token, resourceName, scope, 
1683                    envParameters); 
1684        } else {
1685            DEBUG.error("PolicyEvaluator: invalid request scope: " + scope);
1686            String objs[] = {scope};
1687            throw new PolicyException(ResBundleUtils.rbName,
1688                "invalid_request_scope", objs, null);
1689        }
1690    }
1691
1692    /**
1693     * Gets resource result given a resource name. <code>ResourceResult</code>
1694     * is a tree representation of policy decisions for all resources 
1695     * that are sub resources of argument resource name. 
1696     *
1697     * @param token single sign on token of the user evaluating policies
1698     * @param resourceName name of the resource 
1699     * @param scope indicates whether to compute the resource result based on
1700     *              the policy decision for only the <code>resourceName</code>
1701     *              or all the resources associated with the resource name.
1702     * @param envParameters run-time environment parameters
1703     *
1704     * @return <code>ResourceResult</code>.
1705     *
1706     * @exception SSOException if <code>token</code> is invalid
1707     * @exception PolicyException for any other abnormal condition
1708     *
1709     * @see ResourceMatch#EXACT_MATCH
1710     * @see ResourceMatch#SUB_RESOURCE_MATCH
1711     * @see ResourceMatch#WILDCARD_MATCH
1712     *
1713     */
1714    private ResourceResult getResourceResultTree(SSOToken token, 
1715            String resourceName, String scope, Map envParameters)
1716            throws PolicyException, SSOException {
1717
1718        String userSSOTokenIDStr =  (token != null) 
1719                ? token.getTokenID().toString() 
1720                : PolicyUtils.EMPTY_STRING;
1721
1722        if (token == null) {
1723            if (DEBUG.messageEnabled()) {
1724                DEBUG.message("user sso token is null, forcing ResourceResult"
1725                        + " evaluation to self_scope");
1726            }
1727            scope = ResourceResult.SELF_SCOPE;
1728
1729        }
1730
1731        ResourceResult resourceResult = null;
1732
1733        if ( (resourceName == null) || (resourceName.equals("")) ) {
1734            resourceName = Rule.EMPTY_RESOURCE_NAME;
1735        }
1736        resourceName = serviceType.canonicalize(resourceName);
1737        Map clientEnv = PolicyUtils.cloneMap(envParameters);
1738
1739
1740        // check if we already have the result in the cache
1741        // policyResultsCache: 
1742        // serviceType -> resource -> sessionId -> scope -> result
1743        synchronized(policyResultsCache) {
1744            // rscCACHE: resource -> sessionId -> scope -> result
1745            Map rscCache = (Map)policyResultsCache.get(serviceTypeName);
1746            if (rscCache != null) {
1747                // resultCACHE: sessionId -> scope -> resourceResult
1748                Map resultsCache = (Map)rscCache.get(resourceName);
1749                if (resultsCache != null) {
1750                    Map results = (Map)resultsCache.get(userSSOTokenIDStr);
1751                    if (results != null) {
1752                        resourceResult = (ResourceResult)results.get(scope);
1753                        if (resourceResult != null) {
1754                            long currentTime = System.currentTimeMillis();
1755                            long ttlMinimal = resourceResult.getTimeToLive();
1756                            if (ttlMinimal > currentTime) {
1757
1758                                //check envMap equality of request and cache
1759                                Map cachedEnv = resourceResult.getEnvMap();
1760                                if ( ((clientEnv == null) 
1761                                            && (cachedEnv == null))
1762                                        || ((clientEnv != null)
1763                                            && clientEnv.equals(cachedEnv)) ) {
1764                                    if (DEBUG.messageEnabled()) {
1765                                        DEBUG.message("PolicyEvaluator."
1766                                        + " getResourceResult(): we get the "
1767                                        + "result from the cache.\n" 
1768                                        + resourceResult.toXML());
1769                                    }
1770                                    return resourceResult;
1771                                } else {
1772                                    if (PolicyManager.debug.messageEnabled()) {
1773                                        PolicyManager.debug.message(
1774                                        "PolicyEvaluator.getResourceesultTree()"
1775                                        + ":cached envMap does not equal "
1776                                        + "request envMap, request envMap = " 
1777                                        + clientEnv 
1778                                        + ", cachedEnv=" + cachedEnv
1779                                        );
1780                                    }
1781                                }
1782                            }
1783                        }
1784                    }
1785                }
1786            }
1787        }
1788
1789        /* compute all action names if passed in actionNames is
1790           null or empty */
1791        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
1792            actionNames = serviceType.getActionNames();
1793        }
1794
1795        if (DEBUG.messageEnabled()) {
1796            DEBUG.message("PolicyEvaluator:computing policy decisions "
1797                    + " for resource : " + resourceName);
1798        }
1799        PolicyDecision policyDecision = getPolicyDecision(token, resourceName,
1800                actionNames, envParameters);
1801        resourceResult =  new ResourceResult(resourceName, policyDecision);
1802
1803        if (ResourceResult.SUBTREE_SCOPE.equals(scope)) {
1804            ResourceResult virtualResourceResult 
1805                    = new ResourceResult(ResourceResult.VIRTUAL_ROOT, 
1806                    new PolicyDecision());
1807            virtualResourceResult.addResourceResult(resourceResult, 
1808                    serviceType);
1809            resourceResult = virtualResourceResult;
1810        }
1811
1812        if (ResourceResult.SUBTREE_SCOPE.equals(scope)
1813                || ResourceResult.STRICT_SUBTREE_SCOPE.equals(scope)) {
1814            Map resourceNamesCache    
1815                    = (Map)resourceNamesMap.get(serviceTypeName);
1816            if (resourceNamesCache == null) {
1817                resourceNamesCache = new Cache(resultsCacheResourceCap);
1818                resourceNamesMap.put(serviceTypeName, resourceNamesCache);
1819            }
1820            Set resourceNames = (Set)resourceNamesCache.get(resourceName);
1821            if (resourceNames == null) {
1822                if (DEBUG.messageEnabled()) {
1823                    DEBUG.message("Computing subresources for:  "
1824                            + resourceName);
1825                }
1826                // true indicates to follow referral
1827                resourceNames = getResourceNames(token, resourceName, true);
1828                resourceNames = removeDuplicateResourceNames(resourceNames,
1829                        serviceType);
1830                resourceNames = removeResourceName(resourceNames,
1831                        serviceType, resourceName);
1832                resourceNamesCache.put(resourceName, resourceNames);
1833            }
1834            if (DEBUG.messageEnabled()) {
1835                DEBUG.message("PolicyEvaluator:computing policy decisions "
1836                        + " for subresources : " + resourceNames);
1837            }
1838
1839            Iterator resourceNameIter = resourceNames.iterator();
1840            while (resourceNameIter.hasNext()) {
1841                String subResourceName = (String) resourceNameIter.next();
1842                if (ResourceResult.SUBTREE_SCOPE.equals(scope) ||
1843                        (serviceType.compare(resourceName,
1844                        subResourceName, false).equals(
1845                        ResourceMatch.SUB_RESOURCE_MATCH))) {
1846                    PolicyDecision pDecision = getPolicyDecision(token, 
1847                            subResourceName, actionNames, envParameters);
1848                    resourceResult.addResourceResult(
1849                            new ResourceResult(subResourceName, pDecision),
1850                            serviceType);
1851                }
1852            }
1853        }
1854  
1855        // Do not cache policy decision with advices
1856        if ( (resourceResult != null) 
1857                    && !resourceResult.hasAdvices()) {
1858            resourceResult.setEnvMap(clientEnv);
1859            // add the evaluation result to the result cache
1860            Map scopeElem = null;
1861            //cacheElem: sessionId -> scope -> resourceResult
1862            Map cacheElem = null;
1863            Map rscElem = null;
1864            // serviceType -> resourceName -> sessionId -> scope -> resourceResult
1865            synchronized(policyResultsCache) { 
1866                // rscElemCACHE: resourceName -> sessionId -> scope -> resourceResult
1867                rscElem = (Map)policyResultsCache.get(
1868                                                serviceTypeName);
1869                if (rscElem != null) { // serviceType has been seen earlier
1870                    //CACHEElem: sessionId -> scope -> resourceResult
1871                    cacheElem = (Map)rscElem.get(resourceName);
1872                    if (cacheElem != null) { // resource seen earlier
1873                        scopeElem = (Map)cacheElem.get(
1874                                                userSSOTokenIDStr);
1875                        if (scopeElem == null) { // seeing sessionId first time
1876                            scopeElem = new HashMap();
1877                        }
1878                    } else { // seeing the resource first time
1879                        if (PolicyManager.debug.messageEnabled()) {
1880                            PolicyManager.debug.message(
1881                                "PolicyEvaluator.getResourceResultTree()"
1882                                + " Create Cache for:" 
1883                                + ", resourceName=" + resourceName
1884                                + ", sessionId=" + userSSOTokenIDStr
1885                                + ", scope=" + scope);
1886                        }
1887                        cacheElem = new Cache(resultsCacheSessionCap); 
1888                        scopeElem = new HashMap();
1889                    }
1890                } else { // seeing service for first time
1891                    // rscElemCACHE: resourceName -> sessionId -> scope -> resourceResult
1892                    rscElem = new Cache(resultsCacheResourceCap);
1893                    //CACHEElem: sessionId -> scope -> resourceResult
1894                    if (PolicyManager.debug.messageEnabled()) {
1895                            PolicyManager.debug.message(
1896                                "PolicyEvaluator.getResourceResultTree()"
1897                                + " Create Cache for:" 
1898                                + ", resourceName=" + resourceName
1899                                + ", sessionId=" + userSSOTokenIDStr
1900                                + ", scope=" + scope
1901                                + ", serviceType=" + serviceTypeName);
1902                    }
1903                    cacheElem = new Cache(resultsCacheSessionCap);
1904                    scopeElem = new HashMap();
1905                }
1906                scopeElem.put(scope, resourceResult);
1907                cacheElem.put(userSSOTokenIDStr, scopeElem);
1908                if (PolicyManager.debug.messageEnabled()) {
1909                        PolicyManager.debug.message(
1910                            "PolicyEvaluator.getResourceResultTree()"
1911                            + " Create Cache for:" 
1912                            + ", resourceName=" + resourceName
1913                            + ", sessionId=" + userSSOTokenIDStr
1914                            + ", scope=" + scope
1915                            + ", cacheSize=" + cacheElem.size());
1916                }
1917                rscElem.put(resourceName, cacheElem);
1918                policyResultsCache.put(serviceTypeName, rscElem);
1919            } 
1920
1921            if ( (token != null) 
1922                        && !(ssoListenerRegistry.containsKey(
1923                        userSSOTokenIDStr))) {
1924                try {
1925                    token.addSSOTokenListener(ssoListener);
1926                } catch (SSOException se) {
1927                    DEBUG.error("PolicyEvaluator:"
1928                            + "failed to add sso token listener");
1929                }
1930                ssoListenerRegistry.put(userSSOTokenIDStr, ssoListener);
1931                if (DEBUG.messageEnabled()) {
1932                    DEBUG.message("PolicyEvaluator.getResourceResultTree():"
1933                            + " sso listener added .\n");
1934                }
1935            }
1936            if (DEBUG.messageEnabled()) {
1937                DEBUG.message("PolicyEvaluator: we added the evaluation "
1938                        + " result to the cache");
1939            }
1940        } 
1941
1942        return resourceResult;
1943    }
1944
1945
1946    /**
1947     * Gets resource names that are exact matches, sub resources or 
1948     * wild card matches of argument resource name.
1949     * To determine whether to include a
1950     * resource name of a resource,  we compare argument resource name and 
1951     * policy resource name, treating wild characters in the policy 
1952     * resource name as wild. If the comparison resulted in
1953     * <code>EXACT_MATCH</code>, <code>WILD_CARD_MACTH</code> or
1954     * <code>SUB_RESOURCE_MACTH</code>, the resource result would be
1955     * included.
1956     *
1957     * @param token single sign on token
1958     *
1959     * @param resourceName resoure name
1960     * @param followReferral indicates whether to follow the referrals 
1961     *                       defined in policies to compute resource names
1962     * @return names of sub resources for the given <code>resourceName</code>.
1963     *         The return value would also include the
1964     *         <code>resourceName</code>.
1965     *
1966     * @exception SSOException if <code>token</code> is invalid
1967     * @exception PolicyException for any other abnormal condition
1968     *
1969     * @see ResourceMatch#EXACT_MATCH
1970     * @see ResourceMatch#SUB_RESOURCE_MATCH
1971     * @see ResourceMatch#WILDCARD_MATCH
1972     *
1973     */
1974     public Set getResourceNames(SSOToken token, String resourceName, 
1975             boolean followReferral) throws PolicyException, SSOException {
1976         Set visitedOrgs = new HashSet();
1977         visitedOrgs.add(policyManager.getOrganizationDN());
1978         return getResourceNames(token, resourceName, followReferral,
1979                 visitedOrgs);
1980     }
1981
1982    /**Gets resource names that are exact matches, sub resources or 
1983     * wild card matches of argument resource name.
1984     * To determine whether to include a
1985     * resource name of a resource,  we compare argument resource name and 
1986     * policy resource name, treating wild characters in the policy 
1987     * resource name as wild. If the comparsion resulted in 
1988     * <code>EXACT_MATCH</code>, <code>WILD_CARD_MACTH</code> or 
1989     * <code>SUB_RESOURCE_MACTH</code>, the resource result would be
1990     * included.
1991     *
1992     * @param token single sign on token
1993     *
1994     * @param resourceName resoure name
1995     * @param followReferral indicates whether to follow the referrals 
1996     *                       defined in policies to compute resource names
1997     * @param visitedOrgs organizations that were already visited to 
1998     *                    compute resource names
1999     * @return names of sub resources for the given <code>resourceName</code>.
2000     *         The return value would also include the
2001     *         <code>resourceName</code>.
2002     *
2003     * @exception SSOException if <code>token</code> is invalid
2004     * @exception PolicyException for any other abnormal condition
2005     *
2006     * @see ResourceMatch#EXACT_MATCH
2007     * @see ResourceMatch#SUB_RESOURCE_MATCH
2008     * @see ResourceMatch#WILDCARD_MATCH
2009     *
2010     */
2011     public Set getResourceNames(SSOToken token, String resourceName, 
2012             boolean followReferral, Set visitedOrgs) 
2013             throws PolicyException, SSOException {
2014         DEBUG.message("PolicyEvaluator.getResourceNames():entering");
2015         Set resourceNames = new HashSet();
2016         Set policyNameSet = null;
2017         Set toRemovePolicyNameSet = null;
2018         Set orgsToVisit = new HashSet();
2019         policyNameSet = resourceIndexManager.getSubResourcePolicyNames(
2020                serviceType, resourceName);
2021         policyNameSet.addAll(
2022                resourceIndexManager.getPolicyNames(serviceType,
2023                resourceName, true)); //include policies of super resources
2024         policyNameSet.addAll(
2025                resourceIndexManager.getWildSubResourcePolicyNames(
2026                serviceType, resourceName));
2027         if ( (policyNameSet != null) && (!policyNameSet.isEmpty()) ) {
2028             Iterator policyIter = policyNameSet.iterator();
2029             while (policyIter.hasNext()) {
2030                 String policyName = (String) policyIter.next();
2031                 Policy policy = policyManager.getPolicy(policyName, 
2032                        USE_POLICY_CACHE);
2033                 // policy could have been deleted
2034                 if ( policy != null && policy.isActive()) {
2035                     // true inidicates to follow referrals
2036                     Set pResourceNames = policy.getResourceNames(token, 
2037                             serviceTypeName, resourceName, true);
2038                     if (pResourceNames != null) {
2039                         resourceNames.addAll(pResourceNames);
2040                     }
2041                 } else { // add policy names to toRemovePolicyNameSet
2042                    if (toRemovePolicyNameSet == null) {
2043                        toRemovePolicyNameSet = new HashSet();
2044                    }
2045                    toRemovePolicyNameSet.add(policyName);
2046                    if ( DEBUG.messageEnabled() ) {
2047                        DEBUG.message("PolicyEvaluator.getResourceNames():"
2048                            +policyName+ " is inactive or non-existent");
2049                    }
2050                 }
2051             }
2052             // remove inactive/missing policies from policyNameSet
2053             if (toRemovePolicyNameSet != null) {
2054                 policyNameSet.removeAll(toRemovePolicyNameSet);
2055             }
2056
2057             orgsToVisit.addAll(getOrgsToVisit(policyNameSet));
2058
2059             if ( DEBUG.messageEnabled() ) {
2060                 DEBUG.message("PolicyEvaluator.getResourceNames():"
2061                     + "realmAliasEnabled=" 
2062                     + PolicyConfig.orgAliasMappedResourcesEnabled()
2063                     + ", serviceTypeName=" + serviceTypeName);
2064             }
2065         }
2066         if (PolicyConfig.orgAliasMappedResourcesEnabled()
2067                && PolicyManager.WEB_AGENT_SERVICE.equalsIgnoreCase(
2068                serviceTypeName)) {
2069             String orgAlias = policyManager.getOrgAliasWithResource(
2070                    resourceName); 
2071             if (orgAlias != null) {
2072                 String orgWithAlias = policyManager.getOrgNameWithAlias(
2073                        orgAlias);
2074                 if (orgWithAlias != null) {
2075                     if ( DEBUG.messageEnabled() ) {
2076                         DEBUG.message("PolicyEvaluator."
2077                                 + "getgetResourceNames():"
2078                                 + "adding orgWithAlias to orgsToVisit="
2079                                 + orgWithAlias);
2080                     }
2081                     orgsToVisit.add(orgWithAlias);
2082                 } else {
2083                     if ( DEBUG.messageEnabled() ) {
2084                         DEBUG.message("PolicyEvaluator."
2085                                 + "getgetResourceNames():"
2086                                 + "no realm matched orgAlias:" + orgAlias);
2087                     }
2088                 }
2089             }
2090         }
2091
2092         orgsToVisit.removeAll(visitedOrgs);
2093         while (!orgsToVisit.isEmpty() ) {
2094             String orgToVisit = (String) orgsToVisit.iterator().next();
2095             orgsToVisit.remove(orgToVisit);
2096             visitedOrgs.add(orgToVisit);
2097             //resourceNames.add(resourceName);
2098             try {
2099                 // need to use admin sso token here. Need all privileges to
2100                 // check for the organzation
2101                 policyManager.verifyOrgName(orgToVisit);
2102             } catch (NameNotFoundException nnfe) {
2103                 if( DEBUG.warningEnabled()) {
2104                     DEBUG.warning("PolicyEvaluator."
2105                            + "getgetResourceNames():"
2106                             + "Organization does not exist - "
2107                             + "skipping referral to " + orgToVisit);
2108                 }
2109                 continue;
2110             }
2111             PolicyEvaluator pe = new PolicyEvaluator(orgToVisit, 
2112                    serviceTypeName);
2113             resourceNames.addAll(pe.getResourceNames(token, 
2114                    resourceName, true,
2115                    visitedOrgs)); 
2116         }
2117         return resourceNames; 
2118     }
2119
2120     /** Adds a policy listener that would be notified whenever a policy
2121      *  is added, removed or changed
2122      *
2123      *  @param policyListener the listener to be added
2124      * 
2125      * @supported.api
2126      */
2127      public void addPolicyListener(PolicyListener policyListener) {
2128          policyCache.addPolicyListener(policyListener);
2129      }
2130
2131     /** Removes a policy listener that was previously registered 
2132      *  to receive notifications whenever a policy is added, removed
2133      *  or changed. It is not an error to attempt to remove a listener
2134      *  that was not registered. It would return silently.
2135      *
2136      *  @param policyListener the listener to be removed
2137      * 
2138      * @supported.api
2139      */
2140      public void removePolicyListener(PolicyListener policyListener) {
2141          policyCache.removePolicyListener(policyListener);
2142      }
2143     
2144      /** Merges two policy decisions.
2145       *  Merging policy decisions merges each action decision of the 
2146       *  policy with the corresponding action decision of the other 
2147       *  policy. This method also merges ResponseProviderDecision of one
2148       *  policy ( response attributes per policy) 
2149       *  with that of the other policy.
2150       *  These are the rules followed to merge each action decision:
2151       *  If the action schema has boolean syntax, boolean false value
2152       *  overrides boolean true value. The time to live of boolean false 
2153       *  value overrides the time to live of boolean true value.
2154       *  Otherwise, action values are simply  aggregated. Time to live
2155       *  is set to the minimum of time to live(s) of all values of the
2156       *  action.
2157       *  For response attributes, all response attributes are aggregated.
2158       *  In case of mutiple values for the same attribute 
2159       *  they appear as multi valued data for the attribute.
2160       *  @param serviceType service type that would be consulted to merge the
2161       *         policy decisions
2162       *  @param pd1 policy decision 1
2163       *  @param pd2 policy decision 2
2164       *  @return the merged policy decision. 
2165       *          Policy decisions pd1 and pd2 are merged into pd2 and 
2166       *          pd2 is returned.
2167       */
2168       static PolicyDecision mergePolicyDecisions(ServiceType
2169            serviceType, PolicyDecision pd1, PolicyDecision pd2) {
2170          Map actionDecisions1 = pd1.getActionDecisions();
2171          Set actions = new HashSet();
2172          actions.addAll(actionDecisions1.keySet());
2173          Iterator iter = actions.iterator();
2174          while ( iter.hasNext() ) {
2175              String action = (String) iter.next();
2176              ActionDecision ad1 = (ActionDecision) actionDecisions1.get(
2177                    action);
2178              pd2.addActionDecision(ad1, serviceType);
2179          }
2180          Map mergedReponseAttrsMap = new HashMap();
2181          PolicyUtils.appendMapToMap(pd1.getResponseAttributes(),
2182                mergedReponseAttrsMap);
2183          PolicyUtils.appendMapToMap(pd2.getResponseAttributes(), 
2184                mergedReponseAttrsMap);
2185          pd2.setResponseAttributes(mergedReponseAttrsMap);
2186          return pd2;
2187      }
2188
2189      /** Gets a set of action names for which final values have been 
2190       *  determined. We assume the final values have been determined
2191       *  for an action if the action schema syntax is boolean and 
2192       *  the value is boolean false value
2193       *
2194       *  @param serviceType service type that would be consulted to decide
2195       *         the final values for actions
2196       *  @param pd policy decision 
2197       */
2198      static Set getFinalizedActions(ServiceType
2199            serviceType, PolicyDecision pd) {
2200        Set finalizedActions = new HashSet();
2201        Map actionDecisions = pd.getActionDecisions();
2202        Iterator actions = actionDecisions.keySet().iterator();
2203        while ( actions.hasNext() ) {
2204            String action = (String) actions.next();
2205            ActionDecision actionDecision 
2206                  = (ActionDecision) actionDecisions.get(action);
2207            Set values = actionDecision.getValues();
2208            if ( (values != null) && !values.isEmpty() ) {
2209                try {
2210                    ActionSchema schema 
2211                            = serviceType.getActionSchema(action);
2212                    if ((AttributeSchema.Syntax.BOOLEAN.equals(
2213                                schema.getSyntax()))
2214                                && values.contains(schema.getFalseValue()) ) {
2215                        finalizedActions.add(action);
2216                    }
2217                } catch(InvalidNameException e) {
2218                    DEBUG.error("can not find action schmea for action = " +
2219                            action, e );
2220                }
2221
2222            }
2223              
2224
2225        }
2226        return finalizedActions;
2227      }
2228
2229    /**
2230     *  Gets names of organizations to visit for policy evaluation
2231     *  based on the give policy names.  This is used to follow 
2232     *  OrgReferral(s) defined in the policies
2233     *
2234     *  @return names of organization to visit
2235     *  @exception SSOException if <code>token</code> is invalid
2236     *  @exception PolicyException for any other abnormal condition
2237     */
2238    private Set getOrgsToVisit(Set policyNameSet) 
2239            throws PolicyException, SSOException {
2240        Set orgsToVisit = new HashSet();
2241        Iterator policyNames = policyNameSet.iterator();
2242        while ( policyNames.hasNext() ) {
2243            String policyName = (String) policyNames.next();
2244            Policy policy = policyManager.getPolicy(policyName, 
2245                USE_POLICY_CACHE);
2246            if (policy != null) {
2247                orgsToVisit.addAll(policy.getReferredToOrganizations());
2248            }
2249        }
2250        return orgsToVisit;
2251    }
2252
2253    /**
2254     *   This would be a costly operation.
2255     *   Can be avoided if ResourceName has api for getting canonical name.
2256     *   When the policies are stored, resource names would be converted to and 
2257     *   stored as canonical name.
2258     */
2259    private static Set removeDuplicateResourceNames(Set resourceNames,
2260            ServiceType serviceType) {
2261        Set answer = resourceNames;
2262        if ( (resourceNames != null) && (serviceType != null) ) {
2263            answer = new HashSet(resourceNames.size());
2264            Iterator iter = resourceNames.iterator();
2265            while ( iter.hasNext() ) {
2266                String resourceName = (String) iter.next();
2267                Iterator answerIter = answer.iterator();
2268                boolean duplicate = false;
2269                while (answerIter.hasNext()) {
2270                    String answerResourceName = (String) answerIter.next();
2271
2272                    if ( serviceType.compare(resourceName,
2273                            answerResourceName, false)
2274                            .equals(ResourceMatch.EXACT_MATCH) ) {
2275                        duplicate = true;
2276                        break;
2277                    } 
2278                } 
2279                if (!duplicate) {
2280                    answer.add(resourceName);
2281                }
2282            }
2283
2284        }
2285        return answer;
2286    }
2287
2288    /**
2289     * Removes the <code>resourceName</code> from the <code>Set</code>
2290     * of resource names matching on <code>serviceType</code> and
2291     * performing a <code>ResourceMatch.EXACT_MATCH</code>
2292     */
2293
2294    private static Set removeResourceName(Set resourceNames, 
2295            ServiceType serviceType, String resourceName) {
2296        Set answer = resourceNames;
2297        if ( (resourceNames != null) && (serviceType != null) 
2298                    && (resourceName != null) ) {
2299            answer = new HashSet(resourceNames.size());
2300            answer.addAll(resourceNames);
2301            Iterator iter = resourceNames.iterator();
2302            while ( iter.hasNext() ) {
2303                String rName = (String) iter.next();
2304                if ( serviceType.compare(resourceName,
2305                        rName, false).equals(ResourceMatch.EXACT_MATCH) ) {
2306                    answer.remove(rName);
2307                }
2308            }
2309
2310        }
2311        return answer;
2312    }
2313
2314
2315    /**
2316     * Handles policyChanged notifications - clears the cached resource
2317     * names for the service type name
2318     *
2319     * @param serviceTypeName service type name
2320     * @param pe policy event
2321     */
2322    static void policyChanged(String serviceTypeName, PolicyEvent pe) {
2323
2324        if (DEBUG.messageEnabled()) {
2325            DEBUG.message("PolicyEvaulator.policyChanged():serviceTypeName="
2326                    + serviceTypeName);
2327        }
2328        resourceNamesMap.remove(serviceTypeName);
2329
2330        Cache resourceNamesCache    
2331                = (Cache)resourceNamesMap.get(serviceTypeName);
2332        if ((resourceNamesCache == null) || (resourceNamesCache.isEmpty())) {
2333            return;
2334        }
2335        try {
2336            DEBUG.error("PolicyEvaluator.policyChanged: enterred try block");
2337            ServiceTypeManager stm = ServiceTypeManager.getServiceTypeManager();
2338            ServiceType serviceType = stm.getServiceType(serviceTypeName);
2339            Set resourceNamesToRemove = new HashSet();
2340            synchronized(resourceNamesCache) {
2341                Enumeration resourceNames = resourceNamesCache.keys();
2342                while (resourceNames.hasMoreElements()) {
2343                    String resourceName = (String)resourceNames.nextElement();
2344                    if (resourceNamesToRemove.contains(resourceName)) {
2345                        continue;
2346                    }
2347                    Set affectedResourceNames = pe.getResourceNames();
2348                    Iterator iter = affectedResourceNames.iterator();
2349                    while (iter.hasNext())  {
2350                        String affectedResourceName = (String)iter.next();
2351                        if (serviceType.compare(resourceName, 
2352                                    affectedResourceName)
2353                                    != ResourceMatch.NO_MATCH) {
2354                            resourceNamesToRemove.add(resourceName);
2355                        }
2356                    }
2357                }
2358                Iterator iter1 = resourceNamesToRemove.iterator();
2359                while (iter1.hasNext()) {
2360                    String resourceNameToRemove = (String) iter1.next();
2361                    resourceNamesCache.remove(resourceNameToRemove);
2362                }
2363            }
2364        } catch (SSOException e) {
2365            DEBUG.error("PolicyEvaluator.policyChanged:", e);
2366        } catch (PolicyException pex) {
2367            DEBUG.error("PolicyEvaluator.policyChanged:", pex);
2368        }
2369        if (DEBUG.messageEnabled()) {
2370            DEBUG.message("PolicyEvaulator.policyChanged():serviceTypeName="
2371                    + serviceTypeName
2372                    + ", new cached resoruceNames=" 
2373                    + resourceNamesMap.get(serviceTypeName));
2374        }
2375    }
2376
2377    /**
2378     * Add an advice to the policy decision.
2379     * @param pd <code>PolicyDecision</code> in which to add the advice.
2380     * @param adviceKey key to the condition generating the advice
2381     *        like SessionCondition.SESSION_CONDITION_ADVICE, 
2382     *        AuthSchemeCondition.AUTH_SCHEME_CONDITION_ADVICE
2383     * @param adviceValue advice message to be added to the advice
2384     */
2385    private static void addAdvice(PolicyDecision pd, String adviceKey, 
2386            String adviceValue) {
2387        if ((pd != null) 
2388                    && (pd.hasAdvices())) {
2389            Map actionDecisions = pd.getActionDecisions();
2390            Iterator actionDecisionIter = actionDecisions.keySet().iterator();
2391            while (actionDecisionIter.hasNext()) {
2392                String key = (String) actionDecisionIter.next();
2393                ActionDecision ad = (ActionDecision) actionDecisions.get(key);
2394                Map advices = ad.getAdvices();
2395                if ((advices != null) && !advices.isEmpty()) {
2396                    Set values = (Set)advices.get(adviceKey);
2397                    if (values == null) {
2398                        values = new HashSet();
2399                    }
2400                    values.add(adviceValue);
2401                    advices.put(adviceKey, values);
2402                }
2403            }
2404        }
2405    }
2406
2407    /**
2408     * Get the policy decision for a resource ignoring the subject
2409     */
2410
2411    PolicyDecision getPolicyDecisionIgnoreSubjects(String resourceName, 
2412            Set actionNames, Map env) throws PolicyException, SSOException  {
2413
2414        Set originalResourceNames = new HashSet(2);
2415        originalResourceNames.add(resourceName);
2416
2417        /*
2418         * Add request resourceName and request actionNames to the envParameters
2419         * so that Condition(s)/ResponseProvider(s) can use them if necessary
2420         */
2421        Set resourceNames = new HashSet(2);
2422        resourceNames.add(resourceName);
2423
2424        /* compute for all action names if passed in actionNames is
2425           null or empty */
2426        if ( (actionNames == null) || (actionNames.isEmpty()) ) {
2427            actionNames = serviceType.getActionNames();
2428        }
2429
2430        Set actions = new HashSet();
2431        if (actionNames != null) {
2432            actions.addAll(actionNames);
2433        }
2434
2435        //We create new HashMap in place of empty map since
2436        //Collections.EMPTY_MAP can not be modified
2437        if ((env == null) || env.isEmpty()) {
2438            env = new HashMap();
2439        }
2440
2441        env.put(SUN_AM_REQUESTED_RESOURCE, resourceNames);
2442        env.put(SUN_AM_ORIGINAL_REQUESTED_RESOURCE, 
2443                originalResourceNames);
2444        env.put(SUN_AM_REQUESTED_ACTIONS, actions);
2445        env.put(REALM_DN, asSet(policyManager.getOrganizationDN()));
2446
2447        return getPolicyDecision(null, resourceName, actionNames, env,
2448                new HashSet());
2449    }
2450
2451
2452    /**
2453     * Get the set of role DNs of a user. The role DNs are cached to 
2454     * improve the performance of IdentityServerRole subject membership
2455     * validation.
2456     *
2457     * @param token single sign on token of the user evaluating policies
2458     *
2459     * @return The set of user <code>nsRole</code> attribute values
2460     *
2461     * @exception SSOException single-sign-on token invalid or expired
2462     * @exception PolicyException if an error occured while getting the
2463     *            user's nsRole attribute value set
2464     */
2465     public static Set getUserNSRoleValues(SSOToken token)
2466        throws SSOException, PolicyException {
2467        if (userNSRoleCacheTTL == 0) {
2468            synchronized(userNSRoleCache) {
2469                String orgName = ServiceManager.getBaseDN();
2470                Map pConfigValues = PolicyConfig.getPolicyConfig(orgName);
2471                userNSRoleCacheTTL = 
2472                     PolicyConfig.getSubjectsResultTtl(pConfigValues);
2473                if (userNSRoleCacheTTL <= 0) {
2474                    userNSRoleCacheTTL = DEFAULT_USER_NSROLE_CACHE_TTL;
2475                    if (DEBUG.warningEnabled()) {
2476                        DEBUG.warning("Invalid TTL got from configuration."
2477                                    + " Set TTL to default:" 
2478                                    + userNSRoleCacheTTL);
2479                    }
2480                }
2481                if (DEBUG.messageEnabled()) {
2482                    DEBUG.message("userNSRoleCacheTTL=" 
2483                                   + userNSRoleCacheTTL);
2484                }
2485            }
2486        }
2487        if (token == null) {
2488            return null;
2489        }
2490        String tokenIDStr = token.getTokenID().toString();
2491        Object[] element = (Object[])userNSRoleCache.get(tokenIDStr);
2492        if (element != null) {
2493            Long timeStamp = (Long)element[0];
2494            long timeToLive = 0;
2495            if (timeStamp != null) {
2496                timeToLive = timeStamp.longValue();
2497            }
2498            long currentTime = System.currentTimeMillis();
2499            if (timeToLive > currentTime) {
2500                if (DEBUG.messageEnabled()) {
2501                    DEBUG.message("PolicyEvaluator.getUserNSRoleValues():"
2502                              + " get the nsRole values from cache.\n");
2503                }
2504                return (HashSet)element[1];
2505            }
2506        }
2507        // add or update the cache entry.
2508        // we come here either the token is first registered with the
2509        // cache or the cache element is out of date. 
2510        try {
2511            AMStoreConnection am = new AMStoreConnection(token);
2512            AMUser user = am.getUser(token.getPrincipal().getName());
2513            if ((user == null) || !(user.isActivated())) {
2514                return null;
2515            }
2516            Set roleSet = new HashSet();
2517            Set roles = new HashSet();
2518            // get all the roles assigned to the user
2519            Set staticRoles = user.getRoleDNs();
2520            Set filteredRoles = user.getFilteredRoleDNs();
2521            if (staticRoles != null) {
2522                roles.addAll(staticRoles);
2523            }
2524            if (filteredRoles != null) {
2525                roles.addAll(filteredRoles);
2526            }
2527            if (!roles.isEmpty()) {
2528                Iterator iter = roles.iterator();
2529                while (iter.hasNext()) {
2530                    String role = (String) iter.next();
2531                    if (role != null) { 
2532                        roleSet.add(LDAPUtils.formatToRFC(role));
2533                    }
2534                }
2535            }
2536            if (DEBUG.messageEnabled()) {
2537                DEBUG.message("PolicyEvaluator.getUserNSRoleValues():"
2538                            + " added user nsRoles: " + roleSet);
2539            }
2540            Object[] elem = new Object[2];
2541            elem[0] = new Long(System.currentTimeMillis() 
2542                               + userNSRoleCacheTTL);
2543            elem[1] = roleSet;
2544            userNSRoleCache.put(tokenIDStr, elem);
2545            if (!ssoListenerRegistry.containsKey(tokenIDStr)) {
2546                token.addSSOTokenListener(ssoListener);
2547                ssoListenerRegistry.put(tokenIDStr, ssoListener);
2548                if (DEBUG.messageEnabled()) {
2549                    DEBUG.message("PolicyEvaluator.getUserNSRoleValues():"
2550                            + " sso listener added .\n");
2551                }
2552            }
2553            return roleSet;
2554        } catch (AMException e) {
2555            throw (new PolicyException(e));
2556        }
2557    }
2558
2559    /**
2560     * record stats for policyResultsCache,  ssoListenerRegistry, 
2561     * policyListenerRegistry, userNSRoleCache, resouceNamesMap
2562     */
2563    static void printStats(Stats policyStats) {
2564
2565
2566        int resultsCacheSize = 0;
2567        synchronized (policyResultsCache) {
2568            resultsCacheSize = policyResultsCache.size();
2569        }
2570        policyStats.record("PolicyEvaluator: Number of services in "
2571                + " resultsCache: " + resultsCacheSize);
2572
2573        policyStats.record("PolicyEvaluator: Number of token IDs in "
2574                + " sessionListernerRgistry:"
2575                + ssoListenerRegistry.size());
2576
2577        policyStats.record("PolicyEvaluator: Number of serviceNames "
2578                + " in policyListenerRegistry: "
2579                + policyListenerRegistry.size());
2580
2581        policyStats.record("PolicyEvaluator: Number of token IDs "
2582                + " in role cahce: " + userNSRoleCache.size());
2583
2584        policyStats.record("PolicyEvaluator:Number of serviceNames in "
2585                + " resourceNames cache: " 
2586                + resourceNamesMap.size());
2587    }
2588}