Package org.apache.sling.jcr.resource.internal.helper.jcr

Source Code of org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProvider

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sling.jcr.resource.internal.helper.jcr;

import java.security.Principal;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.query.Query;
import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
import javax.servlet.http.HttpServletRequest;

import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.api.SlingException;
import org.apache.sling.api.adapter.SlingAdaptable;
import org.apache.sling.api.resource.AttributableResourceProvider;
import org.apache.sling.api.resource.DynamicResourceProvider;
import org.apache.sling.api.resource.ModifyingResourceProvider;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.QueriableResourceProvider;
import org.apache.sling.api.resource.QuerySyntaxException;
import org.apache.sling.api.resource.RefreshableResourceProvider;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.apache.sling.jcr.resource.JcrResourceConstants;
import org.apache.sling.jcr.resource.JcrResourceUtil;
import org.apache.sling.jcr.resource.internal.JcrModifiableValueMap;
import org.apache.sling.jcr.resource.internal.NodeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The <code>JcrResourceProvider</code> is the main resource provider of this
* bundle providing access to JCR resources. This resoure provider is created
* for each <code>JcrResourceResolver</code> instance and is bound to the JCR
* session for a single request.
*/
public class JcrResourceProvider
    extends SlingAdaptable
    implements ResourceProvider,
               DynamicResourceProvider,
               AttributableResourceProvider,
               QueriableResourceProvider,
               RefreshableResourceProvider,
               ModifyingResourceProvider {

    /** column name for node path */
    private static final String QUERY_COLUMN_PATH = "jcr:path";

    /** column name for score value */
    private static final String QUERY_COLUMN_SCORE = "jcr:score";

    @SuppressWarnings("deprecation")
    private static final String DEFAULT_QUERY_LANGUAGE = Query.XPATH;

    private static final Set<String> IGNORED_PROPERTIES = new HashSet<String>();
    static {
        IGNORED_PROPERTIES.add(NodeUtil.MIXIN_TYPES);
        IGNORED_PROPERTIES.add(NodeUtil.NODE_TYPE);
        IGNORED_PROPERTIES.add("jcr:created");
        IGNORED_PROPERTIES.add("jcr:createdBy");
    }

    /** Default logger */
    private final Logger log = LoggerFactory.getLogger(getClass());

    /** Flag for closing. */
    private boolean closed = false;

    private final Session session;
    private final ClassLoader dynamicClassLoader;
    private final RepositoryHolder repositoryHolder;

    public JcrResourceProvider(final Session session,
                               final ClassLoader dynamicClassLoader,
                               final RepositoryHolder repositoryHolder) {
        this.session = session;
        this.dynamicClassLoader = dynamicClassLoader;
        this.repositoryHolder = repositoryHolder;
    }

    // ---------- ResourceProvider interface ----------------------------------

    /**
     * @see org.apache.sling.api.resource.ResourceProvider#getResource(org.apache.sling.api.resource.ResourceResolver, javax.servlet.http.HttpServletRequest, java.lang.String)
     */
    @SuppressWarnings("javadoc")
    public Resource getResource(ResourceResolver resourceResolver,
            HttpServletRequest request, String path) throws SlingException {
        return getResource(resourceResolver, path);
    }

    /**
     * @see org.apache.sling.api.resource.ResourceProvider#getResource(org.apache.sling.api.resource.ResourceResolver, java.lang.String)
     */
    public Resource getResource(ResourceResolver resourceResolver, String path)
    throws SlingException {
        this.checkClosed();
        try {
            return createResource(resourceResolver, path);
        } catch (RepositoryException re) {
            throw new SlingException("Problem retrieving node based resource "
                + path, re);
        }

    }

    /**
     * @see org.apache.sling.api.resource.ResourceProvider#listChildren(org.apache.sling.api.resource.Resource)
     */
    public Iterator<Resource> listChildren(final Resource parent) {
        this.checkClosed();

        JcrItemResource parentItemResource;

        // short cut for known JCR resources
        if (parent instanceof JcrItemResource) {

            parentItemResource = (JcrItemResource) parent;

        } else {

            // try to get the JcrItemResource for the parent path to list
            // children
            try {
                parentItemResource = createResource(
                    parent.getResourceResolver(), parent.getPath());
            } catch (RepositoryException re) {
                parentItemResource = null;
            }

        }

        // return children if there is a parent item resource, else null
        return (parentItemResource != null)
                ? parentItemResource.listJcrChildren()
                : null;
    }

    // ---------- implementation helper ----------------------------------------

    /**
     * Creates a <code>Resource</code> instance for the item found at the
     * given path. If no item exists at that path or the item does not have
     * read-access for the session of this resolver, <code>null</code> is
     * returned.
     *
     * @param path The absolute path
     * @return The <code>Resource</code> for the item at the given path.
     * @throws RepositoryException If an error occurrs accessingor checking the
     *             item in the repository.
     */
    private JcrItemResource createResource(final ResourceResolver resourceResolver,
            final String path) throws RepositoryException {
        if (itemExists(path)) {
            Item item = session.getItem(path);
            if (item.isNode()) {
                log.debug(
                    "createResource: Found JCR Node Resource at path '{}'",
                    path);
                return new JcrNodeResource(resourceResolver, path, (Node) item, dynamicClassLoader);
            }

            log.debug(
                "createResource: Found JCR Property Resource at path '{}'",
                path);
            return new JcrPropertyResource(resourceResolver, path,
                (Property) item);
        }

        log.debug("createResource: No JCR Item exists at path '{}'", path);
        return null;
    }

    /**
     * Checks whether the item exists and this content manager's session has
     * read access to the item. If the item does not exist, access control is
     * ignored by this method and <code>false</code> is returned.
     *
     * @param path The path to the item to check
     * @return <code>true</code> if the item exists and this content manager's
     *         session has read access. If the item does not exist,
     *         <code>false</code> is returned ignoring access control.
     */
    private boolean itemExists(final String path) {

        try {
            return session.itemExists(path);
        } catch (RepositoryException re) {
            log.debug("itemExists: Error checking for existence of {}: {}",
                path, re.toString());
            return false;
        }
    }

    /**
     * @see org.apache.sling.api.resource.DynamicResourceProvider#isLive()
     */
    public boolean isLive() {
        return !closed && session.isLive();
    }

    /**
     * @see org.apache.sling.api.resource.DynamicResourceProvider#close()
     */
    public void close() {
        this.repositoryHolder.release();
        this.closed = true;
    }

    /**
     * Check if the resource resolver is already closed.
     *
     * @throws IllegalStateException If the resolver is already closed
     */
    private void checkClosed() {
        if ( this.closed ) {
            throw new IllegalStateException("Resource resolver is already closed.");
        }
    }

    /**
     * @see org.apache.sling.api.resource.QueriableResourceProvider#findResources(ResourceResolver, java.lang.String, java.lang.String)
     */
    public Iterator<Resource> findResources(final ResourceResolver resolver,
                    final String query, final String language) {
        checkClosed();

        try {
            final QueryResult res = JcrResourceUtil.query(session, query, language);
            return new JcrNodeResourceIterator(resolver, res.getNodes(), this.dynamicClassLoader);
        } catch (final javax.jcr.query.InvalidQueryException iqe) {
            throw new QuerySyntaxException(iqe.getMessage(), query, language, iqe);
        } catch (final RepositoryException re) {
            throw new SlingException(re.getMessage(), re);
        }
    }

    /**
     * @see org.apache.sling.api.resource.QueriableResourceProvider#queryResources(ResourceResolver, java.lang.String, java.lang.String)
     */
    public Iterator<ValueMap> queryResources(final ResourceResolver resolver, final String query, final String language) {
        checkClosed();

        final String queryLanguage = isSupportedQueryLanguage(language) ? language : DEFAULT_QUERY_LANGUAGE;

        try {
            QueryResult result = JcrResourceUtil.query(session, query,
                queryLanguage);
            final String[] colNames = result.getColumnNames();
            final RowIterator rows = result.getRows();
            return new Iterator<ValueMap>() {
                public boolean hasNext() {
                    return rows.hasNext();
                };

                public ValueMap next() {
                    final Map<String, Object> row = new HashMap<String, Object>();
                    try {
                        Row jcrRow = rows.nextRow();
                        boolean didPath = false;
                        boolean didScore = false;
                        Value[] values = jcrRow.getValues();
                        for (int i = 0; i < values.length; i++) {
                            Value v = values[i];
                            if (v != null) {
                                String colName = colNames[i];
                                row.put(colName,
                                    JcrResourceUtil.toJavaObject(values[i]));
                                if (colName.equals(QUERY_COLUMN_PATH)) {
                                    didPath = true;
                                }
                                if (colName.equals(QUERY_COLUMN_SCORE)) {
                                    didScore = true;
                                }
                            }
                        }
                        if (!didPath) {
                            row.put(QUERY_COLUMN_PATH, jcrRow.getPath());
                        }
                        if (!didScore) {
                            row.put(QUERY_COLUMN_SCORE, jcrRow.getScore());
                        }

                    } catch (RepositoryException re) {
                        log.error(
                            "queryResources$next: Problem accessing row values",
                            re);
                    }
                    return new ValueMapDecorator(row);
                }

                public void remove() {
                    throw new UnsupportedOperationException("remove");
                }
            };
        } catch (final javax.jcr.query.InvalidQueryException iqe) {
            throw new QuerySyntaxException(iqe.getMessage(), query, language,
                iqe);
        } catch (final RepositoryException re) {
            throw new SlingException(re.getMessage(), re);
        }
    }

    private boolean isSupportedQueryLanguage(final String language) {
        try {
            String[] supportedLanguages = session.getWorkspace().
                getQueryManager().getSupportedQueryLanguages();
            for (String lang : supportedLanguages) {
                if (lang.equals(language)) {
                    return true;
                }
            }
        } catch (final RepositoryException e) {
            log.error("Unable to discover supported query languages", e);
        }
        return false;
    }

    /**
     * @see org.apache.sling.api.resource.AttributableResourceProvider#getAttributeNames(ResourceResolver)
     */
    public Collection<String> getAttributeNames(final ResourceResolver resolver) {
        this.checkClosed();

        final Set<String> names = new HashSet<String>();
        final String[] sessionNames = session.getAttributeNames();
        for(final String name : sessionNames) {
            if ( JcrResourceProviderFactory.isAttributeVisible(name) ) {
                names.add(name);
            }
        }
        return names;
    }

    /**
     * @see org.apache.sling.api.resource.AttributableResourceProvider#getAttribute(ResourceResolver, java.lang.String)
     */
    public Object getAttribute(final ResourceResolver resolver, final String name) {
        this.checkClosed();

        if ( JcrResourceProviderFactory.isAttributeVisible(name) ) {
            if ( ResourceResolverFactory.USER.equals(name) ) {
                return this.session.getUserID();
            }
            return session.getAttribute(name);
        }
        return null;
    }

    /**
     * @see org.apache.sling.api.adapter.SlingAdaptable#adaptTo(java.lang.Class)
     */
    @SuppressWarnings("unchecked")
    @Override
    public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
        if (type == Session.class) {
            return (AdapterType) session;
        } else if (type == Principal.class) {
            try {
                if (this.session instanceof JackrabbitSession && session.getUserID() != null) {
                    JackrabbitSession s =((JackrabbitSession) this.session);
                    final UserManager um = s.getUserManager();
                    if (um != null) {
                        final Authorizable auth = um.getAuthorizable(s.getUserID());
                        if (auth != null) {
                            return (AdapterType) auth.getPrincipal();
                        }
                    }
                }
                log.debug("not able to adapto Resource to Principal, let the base class try to adapt");
            } catch (RepositoryException e) {
                log.warn("error while adapting Resource to Principal, let the base class try to adapt", e);
            }
        }
        return super.adaptTo(type);
    }

    /**
     * @see org.apache.sling.api.resource.ModifyingResourceProvider#create(ResourceResolver, java.lang.String, Map)
     */
    public Resource create(final ResourceResolver resolver, final String path, final Map<String, Object> properties)
    throws PersistenceException {
        // check for node type
        final Object nodeObj = (properties != null ? properties.get(NodeUtil.NODE_TYPE) : null);
        // check for sling:resourcetype
        final String nodeType;
        if ( nodeObj != null ) {
            nodeType = nodeObj.toString();
        } else {
            final Object rtObj =  (properties != null ? properties.get(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY) : null);
            boolean isNodeType = false;
            if ( rtObj != null ) {
                final String resourceType = rtObj.toString();
                if ( resourceType.indexOf(':') != -1 && resourceType.indexOf('/') == -1 ) {
                    try {
                        this.session.getWorkspace().getNodeTypeManager().getNodeType(resourceType);
                        isNodeType = true;
                    } catch (final RepositoryException ignore) {
                        // we expect this, if this isn't a valid node type, therefore ignoring
                    }
                }
            }
            if ( isNodeType ) {
                nodeType = rtObj.toString();
            } else {
                nodeType = null;
            }
        }
        Node node = null;
        try {
            final int lastPos = path.lastIndexOf('/');
            final Node parent;
            if ( lastPos == 0 ) {
                parent = this.session.getRootNode();
            } else {
                parent = (Node)this.session.getItem(path.substring(0, lastPos));
            }
            final String name = path.substring(lastPos + 1);
            if ( nodeType != null ) {
                node = parent.addNode(name, nodeType);
            } else {
                node = parent.addNode(name);
            }

            if ( properties != null ) {
                // create modifiable map
                final JcrModifiableValueMap jcrMap = new JcrModifiableValueMap(node, this.dynamicClassLoader);
                // check mixin types first
                final Object value = properties.get(NodeUtil.MIXIN_TYPES);
                if ( value != null ) {
                    jcrMap.put(NodeUtil.MIXIN_TYPES, value);
                }
                for(final Map.Entry<String, Object> entry : properties.entrySet()) {
                    if ( !IGNORED_PROPERTIES.contains(entry.getKey()) ) {
                        try {
                            jcrMap.put(entry.getKey(), entry.getValue());
                        } catch (final IllegalArgumentException iae) {
                            try {
                                node.remove();
                            } catch ( final RepositoryException re) {
                                // we ignore this
                            }
                            throw new PersistenceException(iae.getMessage(), iae, path, entry.getKey());
                        }
                    }
                }
            }

            return new JcrNodeResource(resolver, path, node, this.dynamicClassLoader);
        } catch (final RepositoryException e) {
            throw new PersistenceException("Unable to create node at " + path, e, path, null);
        }
    }

    /**
     * @see org.apache.sling.api.resource.ModifyingResourceProvider#delete(ResourceResolver, java.lang.String)
     */
    public void delete(final ResourceResolver resolver, final String path)
    throws PersistenceException {
        try {
            if ( session.itemExists(path) ) {
                session.getItem(path).remove();
            } else {
                throw new PersistenceException("Unable to delete resource at " + path + ". Resource does not exist.", null, path, null);
            }
        } catch (final RepositoryException e) {
            throw new PersistenceException("Unable to delete resource at " + path, e, path, null);
        }
    }

    /**
     * @see org.apache.sling.api.resource.ModifyingResourceProvider#revert(ResourceResolver)
     */
    public void revert(final ResourceResolver resolver) {
        try {
            this.session.refresh(false);
        } catch (final RepositoryException ignore) {
            log.warn("Unable to revert pending changes.", ignore);
        }
    }

    /**
     * @see org.apache.sling.api.resource.ModifyingResourceProvider#commit(ResourceResolver)
     */
    public void commit(final ResourceResolver resolver) throws PersistenceException {
        try {
            this.session.save();
        } catch (final RepositoryException e) {
            throw new PersistenceException("Unable to commit changes to session.", e);
        }
    }

    /**
     * @see org.apache.sling.api.resource.ModifyingResourceProvider#hasChanges(ResourceResolver)
     */
    public boolean hasChanges(final ResourceResolver resolver) {
        try {
            return this.session.hasPendingChanges();
        } catch (final RepositoryException ignore) {
            log.warn("Unable to check session for pending changes.", ignore);
        }
        return false;
    }

    /**
     * @see org.apache.sling.api.resource.RefreshableResourceProvider#refresh()
     */
    public void refresh() {
        try {
            this.session.refresh(true);
        } catch (final RepositoryException ignore) {
            log.warn("Unable to refresh session.", ignore);
        }
    }
}
TOP

Related Classes of org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.