/*
* Copyright 2015 Time Warner Cable, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.twcable.jackalope.impl.sling;
import com.day.cq.wcm.api.PageManager;
import com.twcable.jackalope.impl.common.Paths;
import com.twcable.jackalope.impl.cq.PageManagerImpl;
import com.twcable.jackalope.impl.jcr.NodeImpl;
import com.twcable.jackalope.impl.jcr.SessionImpl;
import com.twcable.jackalope.impl.jcr.ValueImpl;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.NonExistingResource;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.jcr.api.SlingRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.jcr.Item;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
/**
* A simple {@link ResourceResolver} suitable for testing.
*/
public class ResourceResolverImpl implements ResourceResolver {
private static final Logger LOG = LoggerFactory.getLogger(ResourceResolverImpl.class);
private final Session session;
private boolean isLive = true;
@SuppressWarnings("ConstantConditions")
public ResourceResolverImpl(@Nonnull SlingRepository repository) {
if (repository == null) throw new IllegalArgumentException("Repository cannot be null.");
try {
this.session = repository.login();
}
catch (RepositoryException re) {
throw new SlingRepositoryException(re);
}
}
@Override
public Resource resolve(HttpServletRequest request, String absPath) {
String path = absPath != null ? absPath : "/";
Resource resource = getResource(path);
return resource != null ? resource : new NonExistingResource(this, path);
}
@Override
public Resource resolve(String absPath) {
return resolve(null, absPath);
}
@Override
public Resource resolve(HttpServletRequest request) {
return resolve(request, null);
}
@Override
public String map(String resourcePath) {
LOG.warn("Resource mapping is not implemented");
return resourcePath; //TODO: implement resource mapping
}
@Override
public String map(HttpServletRequest request, String resourcePath) {
LOG.warn("Resource mapping is not implemented");
return resourcePath; //TODO: implement resource mapping
}
@Override
public Resource getResource(String path) {
try {
return (session.itemExists(path)) ? constructResource(session.getItem(path)) : null;
}
catch (RepositoryException re) {
throw new SlingRepositoryException(re);
}
}
@Override
public Resource getResource(Resource base, String path) {
return getResource(Paths.resolve(base.getPath(), path));
}
@Override
public String[] getSearchPath() {
return new String[0]; //TODO
}
@Override
public Iterator<Resource> listChildren(Resource parent) {
return parent.listChildren();
}
@Override
public Iterable<Resource> getChildren(Resource resource) {
return resource.getChildren();
}
@Override
public Iterator<Resource> findResources(String query, String language) {
return null; //TODO: Implement queries
}
@Override
public Iterator<Map<String, Object>> queryResources(String query, String language) {
return null; //TODO: Implement queries
}
@Override
public boolean hasChildren(Resource resource) {
return listChildren(resource).hasNext();
}
@Override
public ResourceResolver clone(Map<String, Object> authenticationInfo) throws LoginException {
return null; //TODO: Implement authentication
}
@Override
public boolean isLive() {
return isLive;
}
@Override
public void close() {
isLive = false;
}
@Override
public String getUserID() {
return null; //TODO: Implement authentication
}
@Override
public Iterator<String> getAttributeNames() {
return null; //TODO: Implement attributes
}
@Override
public Object getAttribute(String name) {
return null; //TODO: Implement attributes
}
@Override
public void delete(Resource resource) throws PersistenceException {
try {
session.removeItem(resource.getPath());
}
catch (RepositoryException e) {
throw new PersistenceException("Could not delete " + resource.getPath(), e);
}
}
@Override
public Resource create(@Nonnull Resource parent, @Nonnull String name, @Nullable Map<String, Object> properties) throws PersistenceException {
//noinspection ConstantConditions
if (parent == null)
throw new IllegalArgumentException("Could not create a node for \"" + name + "\" because the parent is null");
String parentPath = parent.getPath();
// remove any trailing slash (or sole-slash if the root)
if (parentPath.endsWith("/")) parentPath = parentPath.substring(0, parentPath.length() - 1);
String path = parentPath + "/" + name;
return createNodeResource(path, properties != null ? properties : Collections.<String, Object>emptyMap());
}
private Resource createNodeResource(@Nonnull String path, @Nonnull Map<String, Object> properties) {
try {
if (session.nodeExists(path)) return new NodeResourceImpl(this, session.getNode(path));
}
catch (RepositoryException e) {
//should be impossible since this is in-memory
throw new IllegalStateException(e);
}
try {
NodeImpl node = createNode(path, properties);
return new NodeResourceImpl(this, node);
}
catch (ItemNotFoundException | ItemExistsException e) {
// should be impossible since we're checking first
throw new IllegalStateException(e);
}
}
private NodeImpl createNode(@Nonnull String path, @Nonnull Map<String, Object> properties) throws ItemNotFoundException, ItemExistsException {
NodeImpl node = new NodeImpl((SessionImpl)session, path);
for (String propName : properties.keySet()) {
Object mapVal = properties.get(propName);
setNodeProperty(node, propName, mapVal);
}
return node;
}
private static void setNodeProperty(@Nonnull NodeImpl node, @Nonnull String propName, @Nonnull Object propertyVal) {
try {
node.setProperty(propName, new ValueImpl(propertyVal));
}
catch (RepositoryException ignore) {
// ignore
}
}
@Override
public void revert() {
}
@Override
public void commit() throws PersistenceException {
}
@Override
public boolean hasChanges() {
return false;
}
@Override
public String getParentResourceType(Resource resource) {
return resource.getParent().getResourceType();
}
@Override
public String getParentResourceType(String s) {
return null;
}
@Override
public boolean isResourceType(Resource resource, String resourceType) {
return resource.isResourceType(resourceType);
}
@Override
public void refresh() {
}
@Override
@SuppressWarnings("unchecked")
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
if (type.equals(Session.class)) return (AdapterType)session;
if (type.equals(PageManager.class)) return (AdapterType)new PageManagerImpl(this);
else return null;
}
private Resource constructResource(Item item) {
return (item.isNode()) ? new NodeResourceImpl(this, (Node)item) : new PropertyResourceImpl(this, (Property)item);
}
}