it.cnr.icar.eric.server.query.QueryManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for it.cnr.icar.eric.server.query.QueryManagerImpl.java

Source

/*
 * ====================================================================
 * This file is part of the ebXML Registry by Icar Cnr v3.2 
 * ("eRICv32" in the following disclaimer).
 *
 * "eRICv32" is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * "eRICv32" is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License Version 3
 * along with "eRICv32".  If not, see <http://www.gnu.org/licenses/>.
 *
 * eRICv32 is a forked, derivative work, based on:
 *    - freebXML Registry, a royalty-free, open source implementation of the ebXML Registry standard,
 *      which was published under the "freebxml License, Version 1.1";
 *   - ebXML OMAR v3.2 Edition, published under the GNU GPL v3 by S. Krushe & P. Arwanitis.
 * 
 * All derivative software changes and additions are made under
 *
 * Copyright (C) 2013 Ing. Antonio Messina <messina@pa.icar.cnr.it>
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the freebxml Software Foundation.  For more
 * information on the freebxml Software Foundation, please see
 * "http://www.freebxml.org/".
 *
 * This product includes software developed by the Apache Software
 * Foundation (http://www.apache.org/).
 *
 * ====================================================================
 */
package it.cnr.icar.eric.server.query;

import it.cnr.icar.eric.common.BindingUtility;
import it.cnr.icar.eric.common.CanonicalConstants;
import it.cnr.icar.eric.common.CanonicalSchemes;
import it.cnr.icar.eric.common.CommonResourceBundle;
import it.cnr.icar.eric.common.IterativeQueryParams;
import it.cnr.icar.eric.common.RepositoryItem;
import it.cnr.icar.eric.common.exceptions.ObjectNotFoundException;
import it.cnr.icar.eric.common.spi.QueryManager;
import it.cnr.icar.eric.common.spi.QueryPlugin;
import it.cnr.icar.eric.common.spi.RequestContext;
import it.cnr.icar.eric.server.cache.ServerCache;
import it.cnr.icar.eric.server.cms.CMSManager;
import it.cnr.icar.eric.server.cms.CMSManagerImpl;
import it.cnr.icar.eric.server.common.RegistryProperties;
import it.cnr.icar.eric.server.common.ServerRequestContext;
import it.cnr.icar.eric.server.persistence.PersistenceManager;
import it.cnr.icar.eric.server.persistence.PersistenceManagerFactory;
import it.cnr.icar.eric.server.plugin.AbstractPluginManager;
import it.cnr.icar.eric.server.query.federation.FederatedQueryManager;
import it.cnr.icar.eric.server.repository.RepositoryManager;
import it.cnr.icar.eric.server.repository.RepositoryManagerFactory;
import it.cnr.icar.eric.server.security.authentication.AuthenticationServiceImpl;
import it.cnr.icar.eric.server.security.authorization.AuthorizationResult;
import it.cnr.icar.eric.server.security.authorization.AuthorizationServiceImpl;
import it.cnr.icar.eric.server.util.ServerResourceBundle;

import java.io.StringReader;
import java.math.BigInteger;
import java.security.cert.X509Certificate;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.registry.JAXRException;
import javax.xml.registry.UnsupportedCapabilityException;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.registry.RegistryException;
import org.oasis.ebxml.registry.bindings.query.AdhocQueryRequest;
import org.oasis.ebxml.registry.bindings.query.AdhocQueryResponse;
import org.oasis.ebxml.registry.bindings.query.FilterQueryType;
import org.oasis.ebxml.registry.bindings.query.ResponseOptionType;
import org.oasis.ebxml.registry.bindings.query.ResponseOptionType.ReturnType;
import org.oasis.ebxml.registry.bindings.rim.AdhocQueryType;
import org.oasis.ebxml.registry.bindings.rim.ClassificationNodeType;
import org.oasis.ebxml.registry.bindings.rim.ClassificationSchemeType;
import org.oasis.ebxml.registry.bindings.rim.ExtrinsicObjectType;
import org.oasis.ebxml.registry.bindings.rim.IdentifiableType;
import org.oasis.ebxml.registry.bindings.rim.InternationalStringType;
import org.oasis.ebxml.registry.bindings.rim.LocalizedStringType;
import org.oasis.ebxml.registry.bindings.rim.QueryExpressionType;
import org.oasis.ebxml.registry.bindings.rim.RegistryObjectType;
import org.oasis.ebxml.registry.bindings.rim.RegistryObjectListType;
import org.oasis.ebxml.registry.bindings.rim.RegistryPackageType;
import org.oasis.ebxml.registry.bindings.rim.SlotListType;
import org.oasis.ebxml.registry.bindings.rim.SlotType1;
import org.oasis.ebxml.registry.bindings.rim.UserType;

/**
 * Implements the QueryManager interface for ebXML Registry as defined by ebRS
 * spec.
 * 
 * @author <a href="mailto:Farrukh.Najmi@Sun.COM">Farrukh S. Najmi</a>
 */
public class QueryManagerImpl extends AbstractPluginManager implements QueryManager {

    private static QueryManagerImpl instance = null;

    /* The logger */
    private static Log log = LogFactory.getLog(QueryManagerImpl.class.getName());

    /**
     * @directed
     */
    private it.cnr.icar.eric.server.query.filter.RRFilterQueryProcessor filterQueryProcessor = it.cnr.icar.eric.server.query.filter.RRFilterQueryProcessor
            .getInstance();

    /**
     * @directed
     */
    private it.cnr.icar.eric.server.query.sql.SQLQueryProcessor sqlQueryProcessor = it.cnr.icar.eric.server.query.sql.SQLQueryProcessor
            .getInstance();

    private RepositoryManager rm = RepositoryManagerFactory.getInstance().getRepositoryManager();

    private FederatedQueryManager fqm = null;

    // The prefix for properties that configure a QueryPlugin class
    public static final String QUERY_PLUGIN_PROPERTY_PREFIX = "eric.server.query.plugin";

    // The prefix for properties that configure a QueryFilterPlugin class
    public static final String QUERY_FILTER_PLUGIN_PROPERTY_PREFIX = "eric.server.query.filter.plugin";

    // Key: queryId value: QueryPlugin instance
    Map<String, Object> queryPluginsMap = new HashMap<String, Object>();

    boolean permitAllRead = Boolean
            .valueOf(RegistryProperties.getInstance()
                    .getProperty("eric.security.authorization.enableOverride.permitAllRead", "true"))
            .booleanValue();

    boolean bypassCMS = false;
    CMSManager cmsm = new CMSManagerImpl(); // CMSManagerFactory.getInstance().getContentManagementServiceManager();

    boolean fetchChildObjsSrv = Boolean.valueOf(RegistryProperties.getInstance()
            .getProperty("it.cnr.icar.eric.server.query.fetchChildObjects", "false")).booleanValue();

    protected QueryManagerImpl() {
        bypassCMS = Boolean.valueOf(
                RegistryProperties.getInstance().getProperty("it.cnr.icar.eric.server.query.bypassCMS", "true"))
                .booleanValue();

        // Create and cache QueryPlugins
        getQueryPlugins();

        // Create and cache QueryFilterPlugins
        getQueryFilterPlugins();
    }

    public synchronized static QueryManagerImpl getInstance() {
        if (instance == null) {
            instance = new QueryManagerImpl();
        }

        return instance;
    }

    /**
     * submitAdhocQuery
     */
    @SuppressWarnings({ "static-access", "unchecked" })
    public AdhocQueryResponse submitAdhocQuery(RequestContext context) throws RegistryException {

        AdhocQueryResponse ebAdhocQueryResponse = null;
        context = ServerRequestContext.convert(context);

        AdhocQueryRequest ebAdhocQueryRequest = (AdhocQueryRequest) ((ServerRequestContext) context)
                .getCurrentRegistryRequest();
        ResponseOptionType ebResponseOptionType = ebAdhocQueryRequest.getResponseOption();
        ReturnType returnType = ebResponseOptionType.getReturnType();

        UserType user = ((ServerRequestContext) context).getUser();

        // The result of the query
        RegistryObjectListType ebRegistryObjectListType = null;

        try {
            ebAdhocQueryResponse = null;

            // Process request for the case where it is a parameterized
            // invocation of a stored query
            processForParameterizedQuery((ServerRequestContext) context);

            // TODO: May need a better way than checking
            // getSpecialQueryResults() to know if specialQuery was called.
            if (((ServerRequestContext) context).getSpecialQueryResults() != null) {
                ebAdhocQueryResponse = processForSpecialQueryResults((ServerRequestContext) context);
            } else {
                // Check if it is a federated query and process it using
                // FederatedQueryManager if so.
                boolean isFederated = ebAdhocQueryRequest.isFederated();
                if (isFederated) {
                    // Initialize lazily. Otherwise we have an infinite create
                    // loop
                    if (fqm == null) {
                        fqm = FederatedQueryManager.getInstance();
                    }
                    ebAdhocQueryResponse = fqm.submitAdhocQuery((ServerRequestContext) context);
                } else {
                    int startIndex = ebAdhocQueryRequest.getStartIndex().intValue();
                    int maxResults = ebAdhocQueryRequest.getMaxResults().intValue();
                    IterativeQueryParams paramHolder = new IterativeQueryParams(startIndex, maxResults);

                    org.oasis.ebxml.registry.bindings.rim.AdhocQueryType adhocQuery = ebAdhocQueryRequest
                            .getAdhocQuery();

                    QueryExpressionType queryExp = adhocQuery.getQueryExpression();
                    String queryLang = queryExp.getQueryLanguage();
                    if (queryLang.equals(BindingUtility.CANONICAL_QUERY_LANGUAGE_ID_SQL_92)) {
                        String queryStr = (String) queryExp.getContent().get(0);
                        queryStr = replaceSpecialVariables(user, queryStr);

                        ebRegistryObjectListType = sqlQueryProcessor.executeQuery((ServerRequestContext) context,
                                user, queryStr, ebResponseOptionType, paramHolder);

                        processDepthParameter((ServerRequestContext) context);

                        ebAdhocQueryResponse = BindingUtility.getInstance().queryFac.createAdhocQueryResponse();

                        ebAdhocQueryResponse.setRegistryObjectList(ebRegistryObjectListType);
                        ebAdhocQueryResponse.setStatus(BindingUtility.CANONICAL_RESPONSE_STATUS_TYPE_ID_Success);
                        ebAdhocQueryResponse.setStartIndex(BigInteger.valueOf(paramHolder.startIndex));
                        ebAdhocQueryResponse.setTotalResultCount(BigInteger.valueOf(paramHolder.totalResultCount));

                    } else if (queryLang.equals(BindingUtility.CANONICAL_QUERY_LANGUAGE_ID_ebRSFilterQuery)) {
                        String queryStr = (String) queryExp.getContent().get(0);
                        Unmarshaller unmarshaller = BindingUtility.getInstance().getJAXBContext()
                                .createUnmarshaller();
                        JAXBElement<FilterQueryType> ebFilterQuery = (JAXBElement<FilterQueryType>) unmarshaller
                                .unmarshal(new StreamSource(new StringReader(queryStr)));

                        // take ComplexType from Element
                        FilterQueryType filterQuery = ebFilterQuery.getValue();

                        //                  FilterQueryType filterQuery = (FilterQueryType) queryExp.getContent().get(0);

                        ebRegistryObjectListType = filterQueryProcessor.executeQuery(
                                ((ServerRequestContext) context), user, filterQuery, ebResponseOptionType,
                                paramHolder);

                        ebAdhocQueryResponse = BindingUtility.getInstance().queryFac.createAdhocQueryResponse();
                        ebAdhocQueryResponse.setRegistryObjectList(ebRegistryObjectListType);
                        ebAdhocQueryResponse.setStatus(BindingUtility.CANONICAL_RESPONSE_STATUS_TYPE_ID_Success);
                        ebAdhocQueryResponse.setStartIndex(BigInteger.valueOf(paramHolder.startIndex));
                        ebAdhocQueryResponse.setTotalResultCount(BigInteger.valueOf(paramHolder.totalResultCount));

                    } else {
                        throw new UnsupportedCapabilityException(
                                "Unsupported Query Language: ClassificationNode id: " + queryLang);
                    }
                }
            }

            // fetch child objects
            if (fetchChildObjsSrv) {
                HashMap<String, Object> slotsMap = bu.getSlotsFromRequest(ebAdhocQueryRequest);
                boolean fetchChildObjsClt = Boolean
                        .valueOf((String) slotsMap.get(CanonicalConstants.CANONICAL_SLOT_GET_CHILD_OBJECTS))
                        .booleanValue();
                if (fetchChildObjsClt) {
                    fetchChildObjects(ebAdhocQueryResponse.getRegistryObjectList().getIdentifiable(),
                            (ServerRequestContext) context, ebResponseOptionType);
                }
            }

            // Add repositoryItems to repositoryItemMap if so requested in
            // responseOption
            if (returnType == returnType.LEAF_CLASS_WITH_REPOSITORY_ITEM) {
                addRepositoryItems(ebAdhocQueryResponse.getRegistryObjectList().getIdentifiable(), context);
            }

            if (!bypassCMS) {
                // Now perform any Role-Based Content Filtering on query results
                ((ServerRequestContext) context).getQueryResults().clear();
                ((ServerRequestContext) context).getQueryResults()
                        .addAll(ebAdhocQueryResponse.getRegistryObjectList().getIdentifiable());

                cmsm.invokeServices(((ServerRequestContext) context));
                ebAdhocQueryResponse.getRegistryObjectList().getIdentifiable().clear();
                ebAdhocQueryResponse.getRegistryObjectList().getIdentifiable()
                        .addAll(((ServerRequestContext) context).getQueryResults());

                ((ServerRequestContext) context).getQueryResults().clear();
            }
        } catch (RegistryException e) {
            ((ServerRequestContext) context).rollback();
            throw e;
        } catch (Exception e) {
            ((ServerRequestContext) context).rollback();

            throw new RegistryException(e);
        }

        removeObjectsDeniedAccess(((ServerRequestContext) context),
                ebAdhocQueryResponse.getRegistryObjectList().getIdentifiable());

        if (isQueryFilterRequestBeingMade((ServerRequestContext) context)) {
            // Handle filter query requests
            processForQueryFilterPlugins((ServerRequestContext) context);
            // Filter queries produce special query results
            ebAdhocQueryResponse = processForSpecialQueryResults((ServerRequestContext) context);
        }

        ((ServerRequestContext) context).commit();
        ebAdhocQueryResponse.setRequestId(ebAdhocQueryRequest.getId());

        return ebAdhocQueryResponse;
    }

    @SuppressWarnings("unchecked")
    private AdhocQueryResponse processForSpecialQueryResults(ServerRequestContext context)
            throws RegistryException {
        AdhocQueryResponse ebAdhocQueryResponse = null;
        try {

            // Must have been Optimization for a special query like
            // "urn:oasis:names:tc:ebxml-regrep:query:FindObjectByIdAndType"
            RegistryObjectListType ebRegistryObjectListType = BindingUtility.getInstance().rimFac
                    .createRegistryObjectListType();
            ebRegistryObjectListType.getIdentifiable().addAll((context).getSpecialQueryResults());
            (context).setSpecialQueryResults(null);

            ebAdhocQueryResponse = BindingUtility.getInstance().queryFac.createAdhocQueryResponse();
            ebAdhocQueryResponse.setRegistryObjectList(ebRegistryObjectListType);
            ebAdhocQueryResponse.setStatus(BindingUtility.CANONICAL_RESPONSE_STATUS_TYPE_ID_Success);
            ebAdhocQueryResponse.setStartIndex(BigInteger.valueOf(0));
            ebAdhocQueryResponse.setTotalResultCount(BigInteger.valueOf((context).getQueryResults().size()));
        } catch (Throwable t) {
            throw new RegistryException(t);
        }
        return ebAdhocQueryResponse;
    }

    private boolean isQueryFilterRequestBeingMade(ServerRequestContext context) {
        boolean isQueryFilterRequestBeingMade = false;
        Map<?, ?> map = context.getQueryParamsMap();
        if (map != null) {
            Object obj = map.get("$queryFilterIds");
            if (obj != null) {
                isQueryFilterRequestBeingMade = true;
            }
        }
        return isQueryFilterRequestBeingMade;
    }

    /*
     * This method is used to process any configured QueryFilter plugins
     */
    private void processForQueryFilterPlugins(ServerRequestContext context) throws RegistryException {
        try {
            Map<?, ?> paramsMap = context.getQueryParamsMap();
            if (paramsMap != null) {
                Object obj = context.getQueryParamsMap().get("$queryFilterIds");
                if (obj != null) {
                    if (obj instanceof String) {
                        String filterId = (String) obj;
                        QueryPlugin plugin = (QueryPlugin) queryPluginsMap.get(filterId);
                        plugin.processRequest(context);
                    } else if (obj instanceof Collection) {
                        Collection<?> filterIds = (Collection<?>) obj;
                        Iterator<?> filterItr = filterIds.iterator();
                        while (filterItr.hasNext()) {
                            QueryPlugin plugin = (QueryPlugin) filterItr.next();
                            plugin.processRequest(context);
                        }
                    } else {
                        String msg = ServerResourceBundle.getInstance().getString("invalidFilterQueryParamter",
                                new Object[] { obj.getClass().getName() });
                        throw new RegistryException(msg);
                    }
                }
            }
        } catch (RegistryException re) {
            throw re;
        } catch (Throwable t) {
            throw new RegistryException(t);
        }
    }

    /**
     * Recursively fetches child objects of ClassificationSchemes,
     * ClassificationNodes and RegistryPackages
     */
    private void fetchChildObjects(List<?> objList, ServerRequestContext context, ResponseOptionType responseOption)
            throws RegistryException, JAXBException {

        PersistenceManager pm = PersistenceManagerFactory.getInstance().getPersistenceManager();
        List<?> results = null;
        String sqlQuery = "";

        for (int i = 0; i < objList.size(); i++) {
            ArrayList<String> queryParams = new ArrayList<String>();
            Object identifiable = objList.get(i);

            if (identifiable instanceof ClassificationSchemeType) {
                ClassificationSchemeType ebClassificationSchemeType = (ClassificationSchemeType) identifiable;
                sqlQuery = "SELECT * FROM classificationnode WHERE parent= ?";
                log.trace("Executing query: '" + sqlQuery + "'");
                queryParams.add(ebClassificationSchemeType.getId());
                results = pm.executeSQLQuery(context, sqlQuery, queryParams, responseOption, "classificationnode",
                        new ArrayList<Object>());

                for (int j = 0; j < results.size(); j++) {
                    ClassificationNodeType ebClassificationNodeType = (ClassificationNodeType) results.get(j);
                    ebClassificationSchemeType.getClassificationNode().add(ebClassificationNodeType);
                }

                fetchChildObjects(results, context, responseOption);

            } else if (identifiable instanceof ClassificationNodeType) {
                ClassificationNodeType cn = (ClassificationNodeType) identifiable;
                sqlQuery = "SELECT * FROM classificationnode WHERE parent= ?";
                log.trace("Executing query: '" + sqlQuery + "'");
                queryParams.add(cn.getId());
                results = pm.executeSQLQuery(context, sqlQuery, queryParams, responseOption, "classificationnode",
                        new ArrayList<Object>());

                for (int j = 0; j < results.size(); j++) {
                    ClassificationNodeType ebClassificationNodeType = (ClassificationNodeType) results.get(j);
                    cn.getClassificationNode().add(ebClassificationNodeType);
                }

                fetchChildObjects(results, context, responseOption);

            } else if (identifiable instanceof RegistryPackageType) {
                RegistryPackageType ebRegistryPackageType = (RegistryPackageType) identifiable;
                sqlQuery = "SELECT * FROM registryobject WHERE id in ";
                sqlQuery += "(SELECT ass.targetobject FROM association ass WHERE ass.sourceobject= ? and ";
                sqlQuery += "ass.associationType= ?)";
                log.trace("Executing query: '" + sqlQuery + "'");
                queryParams.add(ebRegistryPackageType.getId());
                queryParams.add(CanonicalSchemes.CANONICAL_ASSOCIATION_TYPE_ID_HasMember);
                results = pm.executeSQLQuery(context, sqlQuery, queryParams, responseOption, "registryobject",
                        new ArrayList<Object>());

                if (results.size() > 0) {
                    ebRegistryPackageType.setRegistryObjectList(
                            BindingUtility.getInstance().rimFac.createRegistryObjectListType());

                    for (int j = 0; j < results.size(); j++) {
                        // create element from complextype
                        JAXBElement<? extends IdentifiableType> ebMember = BindingUtility.getInstance().rimFac
                                .createIdentifiable((IdentifiableType) results.get(j));
                        // add element
                        ebRegistryPackageType.getRegistryObjectList().getIdentifiable().add(ebMember);
                    }
                }

                fetchChildObjects(results, context, responseOption);
            }
        }
    }

    /**
     * Recursively adds RepositoryItems of the ExtrinsicObjects in the
     * <code>regObjs</code> list.
     */
    private void addRepositoryItems(List<JAXBElement<? extends IdentifiableType>> regObjs, RequestContext context)
            throws RegistryException {
        for (int i = 0; i < regObjs.size(); i++) {

            // get ComplexType from Element
            Object obj = regObjs.get(i).getValue();

            if (obj instanceof ExtrinsicObjectType) {
                try {
                    ExtrinsicObjectType ebExtrinsicObjectType = (ExtrinsicObjectType) obj;

                    String id = ebExtrinsicObjectType.getId();
                    RepositoryItem repositoryItem = RepositoryManagerFactory.getInstance().getRepositoryManager()
                            .getRepositoryItem(id);

                    context.getRepositoryItemsMap().put(id, repositoryItem);
                } catch (ObjectNotFoundException onfe) {
                    // ignore, ExtrinsicObject had no RepositoryItem
                }

            } else if (obj instanceof RegistryPackageType) {
                RegistryPackageType ebRegistryPackageType = (RegistryPackageType) obj;
                if (fetchChildObjsSrv && ebRegistryPackageType.getRegistryObjectList() != null
                        && ebRegistryPackageType.getRegistryObjectList().getIdentifiable().size() > 0) {
                    addRepositoryItems(ebRegistryPackageType.getRegistryObjectList().getIdentifiable(), context);
                }
            }
        }
    }

    /**
     * Removes any objects that the user doesn't have authorization to see.
     */
    @SuppressWarnings("unchecked")
    private void removeObjectsDeniedAccess(ServerRequestContext context, @SuppressWarnings("rawtypes") List objs)
            throws RegistryException {

        context.setQueryResults(objs);

        if (permitAllRead) {
            // Optimization: permit auth override to permit all reads
            return;
        }
        AdhocQueryRequest ebAdhocQueryRequest = (AdhocQueryRequest) context.getCurrentRegistryRequest();

        // Remove any objects from the ad-hoc query result set that the
        // user is not permitted to see.
        AuthorizationResult authRes = AuthorizationServiceImpl.getInstance().checkAuthorization((context));

        if (authRes.getDeniedResources().size() > 0) {
            if (isIterativeQuery(ebAdhocQueryRequest)) {
                int size = objs.size();
                for (int i = 0; i < size; i++) {
                    IdentifiableType identifiableObject = (IdentifiableType) objs.get(i);
                    String id = identifiableObject.getId();
                    if (authRes.getDeniedResources().contains(id)) {
                        objs.remove(i);
                        // 'Replace denied resource with placeholder object
                        // Use lightweight object, RegistryPackage
                        // Workaround for bug - bugster id: 6239592
                        RegistryPackageType ebRegistryPackageType = BindingUtility.getInstance().rimFac
                                .createRegistryPackageType();
                        ebRegistryPackageType.setObjectType(
                                "urn:oasis:names:tc:ebxml-regrep:ObjectType:RegistryObject:RegistryPackage");
                        InternationalStringType iString = BindingUtility.getInstance().rimFac
                                .createInternationalStringType();
                        LocalizedStringType ebLocalizedStringType = BindingUtility.getInstance().rimFac
                                .createLocalizedStringType();
                        // We'll i18n this string soon
                        ebLocalizedStringType.setValue("(Access Denied)");
                        ebLocalizedStringType.setLang("en-US");
                        ebLocalizedStringType.setCharset("UTF-8");
                        iString.getLocalizedString().add(ebLocalizedStringType);
                        ebRegistryPackageType.setName(iString);
                        objs.add(i, ebRegistryPackageType);

                        // TODO: Should not expose an actual id to unauthorized
                        // clients
                        ebRegistryPackageType.setId(id);
                        ebRegistryPackageType.setLid(id);
                    }
                }
            } else {
                Iterator<RegistryObjectType> queryResultsIter = objs.iterator();
                while (queryResultsIter.hasNext()) {
                    IdentifiableType identifiableObject = queryResultsIter.next();
                    String id = identifiableObject.getId();
                    if (authRes.getDeniedResources().contains(id)) {
                        queryResultsIter.remove();
                    }
                }
            }
        }

        context.setQueryResults(objs);
    }

    /**
     * Process optional impl specific depth paramater specified as request Slot.
     * If present, prefetches referenced objects up to specified depth level.
     * Depth = 0 (default) implies only fetch matched objects. Depth = n
     * implies, also fetch all objects referenced by matched objects upto depth
     * of n Depth = -1 implies, also fetch all objects referenced by matched
     * objects upto any level. Direct and indirect circular references are
     * handled to avoid infinite loop.
     */
    private void processDepthParameter(ServerRequestContext context) throws RegistryException {
    }

    private boolean isIterativeQuery(AdhocQueryRequest ebAdhocQueryRequest) {
        return (ebAdhocQueryRequest.getMaxResults().intValue() != -1);
        /*
        if (ebAdhocQueryRequest.getMaxResults().intValue() == -1) {
           return false;
        } else {
           return true;
        }
        */
    }

    /**
     * Extracts the queryId and parameters from request and stores it in the
     * context for later use by QueryPlugin.
     * 
     */
    private void getQueryParameters(ServerRequestContext context) throws RegistryException {
        AdhocQueryRequest ebAdhocQueryRequest = (AdhocQueryRequest) (context).getCurrentRegistryRequest();

        SlotListType slotList = ebAdhocQueryRequest.getRequestSlotList();

        if (slotList != null) {
            List<SlotType1> slots = slotList.getSlot();

            HashMap<String, Object> queryParamsMap = new HashMap<String, Object>();
            Iterator<SlotType1> iter = slots.iterator();
            while (iter.hasNext()) {
                SlotType1 slot = iter.next();
                String slotName = slot.getName();
                if (slotName.equals(BindingUtility.CANONICAL_SLOT_QUERY_ID)) {
                    String value = (slot.getValueList().getValue()).get(0);
                    context.setQueryId(value);
                } else if (slotName.charAt(0) == '$') {
                    List<String> vlist = slot.getValueList().getValue();
                    int vListSize = vlist.size();
                    if (vListSize == 1) {
                        String paramValue = vlist.get(0);
                        queryParamsMap.put(slotName, paramValue); // <String,
                        // String>
                    } else if (vListSize > 1) {
                        // Need to support a Collection of Strings
                        Collection<String> stringCollection = new ArrayList<String>(vListSize);
                        Iterator<String> valItr = vlist.iterator();
                        while (valItr.hasNext()) {
                            String value = valItr.next();
                            stringCollection.add(value);
                        }
                        queryParamsMap.put(slotName, stringCollection); // <String,
                        // Collection<String>>
                    }
                }
            }

            context.setQueryParamsMap(queryParamsMap);
        }
    }

    /**
     * Creates and caches all QueryPlugins
     */
    private void getQueryPlugins() {
        RegistryProperties props = RegistryProperties.getInstance();
        Iterator<String> propsIter = props.getPropertyNamesStartingWith(QUERY_PLUGIN_PROPERTY_PREFIX);

        while (propsIter.hasNext()) {
            String prop = propsIter.next();
            String queryId = prop.substring(QUERY_PLUGIN_PROPERTY_PREFIX.length() + 1);
            String pluginClassName = props.getProperty(prop);

            try {
                Object plugin = createPluginInstance(pluginClassName);
                if (!(plugin instanceof QueryPlugin)) {
                    throw new JAXRException(
                            CommonResourceBundle.getInstance().getString("message.unexpectedObjectType",
                                    new String[] { plugin.getClass().toString(), QueryPlugin.class.toString() }));
                }
                queryPluginsMap.put(queryId, plugin);
            } catch (Exception e) {
                log.error(e);
            }
        }

    }

    /**
     * Creates and caches all QueryFilterPlugins
     */
    private void getQueryFilterPlugins() {
        RegistryProperties props = RegistryProperties.getInstance();
        Iterator<String> propsIter = props.getPropertyNamesStartingWith(QUERY_FILTER_PLUGIN_PROPERTY_PREFIX);

        while (propsIter.hasNext()) {
            String prop = propsIter.next();
            String queryId = prop.substring(QUERY_FILTER_PLUGIN_PROPERTY_PREFIX.length() + 1);
            String pluginClassName = props.getProperty(prop);

            try {
                Object plugin = createPluginInstance(pluginClassName);
                if (!(plugin instanceof QueryPlugin)) {
                    throw new JAXRException(
                            CommonResourceBundle.getInstance().getString("message.unexpectedObjectType",
                                    new String[] { plugin.getClass().toString(), QueryPlugin.class.toString() }));
                }
                queryPluginsMap.put(queryId, plugin);
            } catch (Exception e) {
                log.error(e);
            }
        }

    }

    /**
     * Gets the QueryPlugin that can process this query.
     * 
     * @return the QueryPlugin if a match is found, otherwise return null
     */
    QueryPlugin getQueryPlugin(ServerRequestContext context) throws RegistryException {
        QueryPlugin plugin = null;

        String queryId = context.getQueryId();

        if (queryId != null) {
            Object o = queryPluginsMap.get(queryId);
            if (o instanceof QueryPlugin) {
                plugin = (QueryPlugin) o;
            }
        }

        return plugin;
    }

    /**
     * Checks if supplied query is a parameterized query. If not return the same
     * query. If stored parameterized query then return a new query after
     * fetching the specified parameterized query from registry, replacing its
     * positional parameters with supplied parameters. If special parameterized
     * query then invoke special query and set its results on
     * context.getSpecialQueryResults(). If neither not a parameterized query at
     * all then simply return the original request.
     */
    private void processForParameterizedQuery(ServerRequestContext context) throws RegistryException {

        // First check if it is a
        AdhocQueryRequest ebAdhocQueryRequest = (AdhocQueryRequest) (context).getCurrentRegistryRequest();

        getQueryParameters(context);
        String queryId = context.getQueryId();
        @SuppressWarnings("unused")
        Map<?, ?> queryParamsMap = context.getQueryParamsMap();

        @SuppressWarnings("unused")
        SlotListType slotList = ebAdhocQueryRequest.getRequestSlotList();

        // If queryId is not null then get the AdhocQuery from registry, plug
        // the parameters
        // and set it as newReq
        if (queryId != null) {
            // This is a parameterized query

            QueryPlugin plugin = getQueryPlugin(context);

            if (plugin != null) {
                // Found a plugin for this queryId. invoke it
                plugin.processRequest(context);
            } else {
                // Must be a stored query since no plugin was found.

                // TODO: Assumes SQLQuery. Needs to support FilterQuery
                AdhocQueryType adhocQuery = (AdhocQueryType) ServerCache.getInstance().getRegistryObject(context,
                        queryId, "AdhocQuery");

                if (adhocQuery == null) {
                    throw new ObjectNotFoundException(queryId, "AdhocQuery");
                }

                try {
                    // Need to make a copy of the query before
                    // plugQueryParameters as the query may be cached and should
                    // not be modified in place.
                    adhocQuery = (AdhocQueryType) BindingUtility.getInstance().cloneRegistryObject(adhocQuery);
                    adhocQuery = plugQueryParameters(adhocQuery, context.getQueryParamsMap(),
                            context.getStoredQueryParams());
                    ebAdhocQueryRequest.setAdhocQuery(adhocQuery);
                } catch (JAXBException e) {
                    throw new RegistryException(e);
                } catch (JAXRException e) {
                    throw new RegistryException(e);
                }
            }
        }
    }

    /**
     * Replaces named parameters in an SQLQuery with ? while placing
     * corresponding positional paramValues in queryParams List.
     * 
     * @param query
     *            the AdhocQuery to be executed
     * @param queryParamsMap
     *            the Map in which each entry is a query param name/value pair
     * @param positionalParamValues
     *            a List of param values for each positional parameter in the
     *            PrepareStatment for the query
     */
    @SuppressWarnings({ "rawtypes", "static-access" })
    private AdhocQueryType plugQueryParameters(AdhocQueryType query, Map queryParamsMap,
            List<String> positionalParamValues) throws JAXBException {
        AdhocQueryType newQuery = query;
        positionalParamValues.clear(); // Start with empty list

        // Get the queryString
        QueryExpressionType queryExp = query.getQueryExpression();
        @SuppressWarnings("unused")
        String queryLang = queryExp.getQueryLanguage();
        String queryStr = (String) queryExp.getContent().get(0);
        String newQueryStr = new String(queryStr);
        log.debug("queryStr=" + queryStr);

        // Now replace parameterNames in queryString with ?
        // and add corresponding paramValue to quereyParams List
        // If a paramName is used more than once in queryString then
        // add corresponding paramValue multiple times in appropriate
        // position in positionalParamValues list
        // This would be easier with JDBC 3.0 nameParameters but support
        // is optional in JDBC 3.0 drivers and therefore not reliable.
        Iterator iter = queryParamsMap.keySet().iterator();

        Map<Integer, String> paramIndexToValueMap = new TreeMap<Integer, String>();

        // Process each $paramName by replacing it with ? in queryStr
        // and placing its paramValue in corresponding index on
        // positionalParamValues
        while (iter.hasNext()) {
            String paramName = (String) iter.next();
            String paramValue = queryParamsMap.get(paramName).toString();

            // Pattern to match $paramName optionally surrounded by single
            // quotes. First OR clause matches the longer option -- with
            // surrounding single quotes. Second OR clause matches
            // isolated parameter name.
            //
            // Some parameter names are prefixes of others ($considerPort
            // and $considerPortType for example) and this complicates the
            // second part. Must ensure we match the name only if it is
            // not a prefix. The zero-width negative lookahead checks this
            // case and does not mess up the replacement. Similar
            // zero-width negative lookbehind at start avoids matching (for
            // example) '$binding.transportType%' since that case would
            // result in '?%' and a parameter the underlying SQL parser
            // won't find. NOTE: Not checking for all parameters "buried"
            // in SQL string literals.
            //
            // TODO: The currently-used parameter name characters are
            // [a-zA-Z0-9.]. This goes beyond both [a-zA-Z0-9] from
            // [ebRS], section 6.3.1.1 and [a-zA-Z0-9_$#] previously in
            // SQLParser.jj. Rule below and latest SQLParser.jj <VARIABLE>
            // production are at least consistent. Should '.' be removed
            // from parameter names in WS Profile? Should both '.' and '_'
            // be disallowed in all parameter names?

            // Use Utility method as following is not in JDK 1.4
            // String quotedParamName = Pattern.quote(paramName);
            String quotedParamName = it.cnr.icar.eric.common.Utility.getInstance().quote(paramName);
            String paramNamePattern = "('" + quotedParamName + "')|" + "((?<!')" + quotedParamName
                    + "(?![a-zA-Z0-9._]))";
            Pattern p = Pattern.compile(paramNamePattern);
            Matcher m = p.matcher(queryStr);

            // Remember start index of each occurance of paramName
            boolean found = false;
            while (m.find()) {
                found = true;
                paramIndexToValueMap.put(new Integer(m.start()), paramValue);
            }

            // Replace substrings matching paramNamePattern with ? Must be
            // done using separate matcher and string to keep
            // paramIndexToValueMap sorted
            if (found) {
                newQueryStr = p.matcher(newQueryStr).replaceAll("?");
            }
        }

        if (paramIndexToValueMap.size() > 0) {
            positionalParamValues.addAll(paramIndexToValueMap.values());
        }

        // Now re-constitute as query
        queryExp.getContent().clear();
        queryExp.getContent().add(newQueryStr);

        return newQuery;
    }

    /**
     * Replaces special environment variables within specified query string.
     */
    private String replaceSpecialVariables(UserType user, String query) {
        String newQuery = query;

        // Replace $currentUser
        if (user != null) {
            newQuery = newQuery.replaceAll("\\$currentUser", "'" + user.getId() + "'");
        }

        // Replace $currentTime
        Timestamp currentTime = new Timestamp(Calendar.getInstance().getTimeInMillis());

        // ??The timestamp is being truncated to work around a bug in PostgreSQL
        // 7.2.2 JDBC driver
        String currentTimeStr = currentTime.toString().substring(0, 19);
        newQuery = newQuery.replaceAll("\\$currentTime", currentTimeStr);

        return newQuery;
    }

    /**
     * Gets RegistryObject matching specified id. This method is added for the
     * REST
     * 
     */
    public RegistryObjectType getRegistryObject(RequestContext context, String id) throws RegistryException {

        return getRegistryObject(context, id, "RegistryObject");
    }

    public RegistryObjectType getRegistryObject(RequestContext context, String id, String typeName)
            throws RegistryException {

        RegistryObjectType ro = null;
        ServerRequestContext serverContext = ServerRequestContext.convert(context);
        boolean doCommit = false;

        try {
            // Code in AuthorizationServiceImpl and else where expects a request
            // so make one up
            AdhocQueryRequest req = BindingUtility.getInstance()
                    .createAdhocQueryRequest("SELECT * FROM DummyTable");
            serverContext.pushRegistryRequest(req);

            UserType user = serverContext.getUser();

            typeName = it.cnr.icar.eric.common.Utility.getInstance().mapTableName(typeName);
            ro = ServerCache.getInstance().getRegistryObject(serverContext, id, typeName);

            // Avoid overhead of access control checks for RegistryOperator
            // internal user
            if ((null != ro) && ((null == user)
                    || (!user.getId().equalsIgnoreCase(AuthenticationServiceImpl.ALIAS_REGISTRY_OPERATOR)))) {
                List<RegistryObjectType> roList = new ArrayList<RegistryObjectType>();
                roList.add(ro);
                removeObjectsDeniedAccess(serverContext, roList);
                if (!(roList.contains(ro))) {
                    ro = null;
                }
            }
            doCommit = true;
        } catch (JAXBException e) {
            log.error(e, e); // Can't happen
        } finally {
            if (context != serverContext) {
                if (doCommit) {
                    serverContext.commit();
                } else {
                    serverContext.rollback();
                }
            } else {
                serverContext.popRegistryRequest();
            }
        }

        return ro;
    }

    /**
     * This method is added for the REST It returns the RepositroyItem give a
     * UUID
     * 
     */
    public RepositoryItem getRepositoryItem(RequestContext context, String id) throws RegistryException {

        RepositoryItem ri = null;
        ServerRequestContext serverContext = ServerRequestContext.convert(context);
        boolean doCommit = false;

        try {
            @SuppressWarnings("unused")
            UserType user = serverContext.getUser();
            // Code in AuthorizationServiceImpl and else where expects a request
            // so make one up
            AdhocQueryRequest req = BindingUtility.getInstance()
                    .createAdhocQueryRequest("SELECT * FROM DummyTable");
            serverContext.pushRegistryRequest(req);

            // Following call is to force access control check which is
            // already implemented in getRegistryObject(...)
            RegistryObjectType ro = getRegistryObject(serverContext, id);
            if (ro != null) {
                ri = rm.getRepositoryItem(id);
            }
            doCommit = true;
        } catch (JAXBException e) {
            log.error(e, e); // Can't happen
        } finally {
            if (context != serverContext) {
                if (doCommit) {
                    serverContext.commit();
                } else {
                    serverContext.rollback();
                }
            } else {
                serverContext.popRegistryRequest();
            }
        }

        return ri;
    }

    /**
     * Gets the RegistryObjects referenced by specified RegistryObject.
     * 
     * @param ro
     *            specifies the RegistryObject whose referenced objects are
     *            being sought.
     * @param depth
     *            specifies depth of fetch. -1 implies fetch all levels. 1
     *            implies fetch immediate referenced objects.
     * 
     *            public Set getReferencedRegistryObjects(RegistryObjectType ro,
     *            int depth) throws RegistryException { HashSet
     *            referencedObjects = new HashSet();
     * 
     *            try { HashMap idMap = new HashMap(); Set immediateObjectRefs =
     *            BindingUtility.getInstance().getObjectRefsInRegistryObject(ro,
     *            idMap);
     * 
     *            --depth;
     * 
     *            //Get each immediately referenced RegistryObject Iterator iter
     *            = immediateObjectRefs.iterator(); while (iter.hasNext()) {
     *            String ref = (String)iter.next(); RegistryObjectType obj =
     *            getRegistryObject(ref);
     * 
     *            referencedObjects.add(obj);
     * 
     *            //If depth != 0 then recurse and get referenced objects for
     *            obj if (depth != 0) {
     *            referencedObjects.addAll(getReferencedRegistryObjects(obj,
     *            depth)); } } } catch (JAXRException e) { throw new
     *            RegistryException(e); }
     * 
     *            return referencedObjects; }
     */

    public UserType getUser(X509Certificate cert) throws RegistryException {
        return AuthenticationServiceImpl.getInstance().getUserFromCertificate(cert);
    }

}