/* * 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.jena.permissions.model.impl; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.apache.jena.enhanced.UnsupportedPolymorphismException; import org.apache.jena.graph.FrontsNode; import org.apache.jena.graph.Node; import org.apache.jena.permissions.impl.ItemHolder; import org.apache.jena.permissions.impl.SecuredItemImpl; import org.apache.jena.permissions.model.SecuredModel; import org.apache.jena.permissions.model.SecuredRDFNode; import org.apache.jena.permissions.model.SecuredUnsupportedPolymorphismException; import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.Resource; import org.apache.jena.shared.AuthenticationRequiredException; import org.apache.jena.shared.ReadDeniedException; /** * Implementation of SecuredRDFNode to be used by a SecuredItemInvoker proxy. */ public abstract class SecuredRDFNodeImpl extends SecuredItemImpl implements SecuredRDFNode { /** * * @param securedModel * the Secured Model to use. * @param rdfNode * the node to secure. * @return the secured RDFNode */ public static SecuredRDFNode getInstance(final SecuredModel securedModel, final RDFNode rdfNode) { if (rdfNode instanceof Literal) { return SecuredLiteralImpl.getInstance(securedModel, (Literal) rdfNode); } else { return SecuredResourceImpl.getInstance(securedModel, (Resource) rdfNode); } } // the item holder that contains this SecuredRDFNode private final ItemHolder<? extends RDFNode, ? extends SecuredRDFNode> holder; // the secured securedModel that contains this node. private final SecuredModel securedModel; /** * Constructor * * @param securedModel * the Secured Model to use. * @param holder * the item holder that will contain this SecuredRDFNode. */ protected SecuredRDFNodeImpl(final SecuredModel securedModel, final ItemHolder<? extends RDFNode, ? extends SecuredRDFNode> holder) { super(securedModel, holder); if (holder.getBaseItem().getModel() == null) { throw new IllegalArgumentException( String.format("Holder base item (%s) must have a securedModel", holder.getBaseItem().getClass())); } this.securedModel = securedModel; this.holder = holder; } @SuppressWarnings("unchecked") @Override public <T extends RDFNode> T as(final Class<T> view) throws ReadDeniedException, AuthenticationRequiredException, SecuredUnsupportedPolymorphismException { checkRead(); // see if the base Item can as T baseAs = holder.getBaseItem().as(view); if (view.equals(SecuredRDFNodeImpl.class) || view.equals(RDFNode.class)) { return (T) this; } final Method m = getConstructor(view); if (m == null) { throw new SecuredUnsupportedPolymorphismException(this, view); } try { return (T) m.invoke(null, securedModel, baseAs); } catch (final UnsupportedPolymorphismException e) { throw new SecuredUnsupportedPolymorphismException(this, view); } catch (final IllegalArgumentException e) { throw new RuntimeException(e); } catch (final IllegalAccessException e) { throw new RuntimeException(e); } catch (final InvocationTargetException e) { throw new RuntimeException(e); } } @Override public Node asNode() throws ReadDeniedException, AuthenticationRequiredException { checkRead(); return holder.getBaseItem().asNode(); } @Override public <T extends RDFNode> boolean canAs(final Class<T> view) throws ReadDeniedException, AuthenticationRequiredException { checkRead(); // see if the base Item can as if (holder.getBaseItem().canAs(view)) { return getConstructor(view) != null; } return false; } private <T extends RDFNode> Method getConstructor(final Class<T> view) { String classNm = SecuredRDFNodeImpl.class.getName(); classNm = String.format("%s.Secured%sImpl", classNm.substring(0, classNm.lastIndexOf(".")), view.getSimpleName()); try { final Class<?> c = Class.forName(classNm); return c.getDeclaredMethod("getInstance", SecuredModel.class, view); } catch (final ClassNotFoundException e) { return null; } catch (final SecurityException e) { return null; } catch (final NoSuchMethodException e) { return null; } } @Override public SecuredModel getModel() { return securedModel; } @Override public RDFNode inModel(final Model m) throws ReadDeniedException, AuthenticationRequiredException { checkRead(); if (securedModel.equals(m)) { return this; } if (m instanceof SecuredModel) { return SecuredRDFNodeImpl.getInstance((SecuredModel) m, holder.getBaseItem().inModel(m)); } return holder.getBaseItem().inModel(m); } @Override public boolean isAnon() { return holder.getBaseItem().isAnon(); } @Override public boolean isLiteral() { return holder.getBaseItem().isLiteral(); } @Override public boolean isResource() { return holder.getBaseItem().isResource(); } @Override public boolean isURIResource() { return holder.getBaseItem().isURIResource(); } /** * An RDFNode is equal to another enhanced node n iff the underlying nodes * are equal. We generalise to allow the other object to be any class * implementing asNode, because we allow other implemementations of * Resource, at least in principle. This is deemed to be a complete and * correct interpretation of RDFNode equality, which is why this method has * been marked final. * * @param o * An object to test for equality with this node * @return True if o is equal to this node. * @throws ReadDeniedException * @throws AuthenticationRequiredException */ @Override final public boolean equals(Object o) throws ReadDeniedException, AuthenticationRequiredException { checkRead(); return o instanceof FrontsNode && asNode().equals(((FrontsNode) o).asNode()); } /** * The hash code of an RDFnode is defined to be the same as the underlying * node. * * @return The hashcode as an int */ @Override final public int hashCode() { return holder.getBaseItem().asNode().hashCode(); } }