View Javadoc

1   /*
2    * Copyright (c) 2007, James Leigh All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    * 
7    * - Redistributions of source code must retain the above copyright notice, this
8    *   list of conditions and the following disclaimer.
9    * - Redistributions in binary form must reproduce the above copyright notice,
10   *   this list of conditions and the following disclaimer in the documentation
11   *   and/or other materials provided with the distribution. 
12   * - Neither the name of the openrdf.org nor the names of its contributors may
13   *   be used to endorse or promote products derived from this software without
14   *   specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   * 
28   */
29  package org.openrdf.elmo.rolemapper;
30  
31  import java.util.Collection;
32  import java.util.Collections;
33  import java.util.HashMap;
34  import java.util.HashSet;
35  import java.util.Map;
36  import java.util.Set;
37  
38  import org.openrdf.elmo.RdfTypeFactory;
39  
40  /**
41   * Tracks recorded roles and maps them to their subject type.
42   * 
43   * @author James Leigh
44   * 
45   */
46  public class HierarchicalRoleMapper<URI> {
47  
48  	private DirectMapper<URI> directMapper;
49  
50  	private TypeMapper<URI> typeMapper;
51  
52  	private SimpleRoleMapper<URI> simpleRoleMapper;
53  
54  	private Map<Class<?>, Set<Class<?>>> subclasses;
55  
56  	public HierarchicalRoleMapper(DirectMapper<URI> directMapper,
57  			TypeMapper<URI> typeMapper, SimpleRoleMapper<URI> simpleRoleMapper) {
58  		this.directMapper = directMapper;
59  		this.typeMapper = typeMapper;
60  		this.simpleRoleMapper = simpleRoleMapper;
61  		subclasses = new HashMap<Class<?>, Set<Class<?>>>(256);
62  	}
63  
64  	public void setRdfTypeFactory(RdfTypeFactory<URI> vf) {
65  		simpleRoleMapper.setRdfTypeFactory(vf);
66  	}
67  
68  	public Class<?>[] findBaseRoles() {
69  		return simpleRoleMapper.findBaseRoles();
70  	}
71  
72  	public Class<?>[] findRoles(URI type) {
73  		return simpleRoleMapper.findRoles(type);
74  	}
75  
76  	public Collection<Class<?>> findRoles(Collection<URI> types,
77  			Collection<Class<?>> classes) {
78  		return simpleRoleMapper.findRoles(types, classes);
79  	}
80  
81  	public boolean isTypeRecorded(URI type) {
82  		return simpleRoleMapper.isTypeRecorded(type);
83  	}
84  
85  	public Collection<URI> findTypes(Class<?> javaClass,
86  			Collection<URI> rdfTypes) {
87  		return typeMapper.findTypes(javaClass, rdfTypes);
88  	}
89  
90  	/**
91  	 * Finds the rdf:Class<?> for this Java Class<?>.
92  	 * 
93  	 * @param javaClass
94  	 * @return URI of the rdf:Class<?> for this Java Class<?> or null.
95  	 */
96  	public URI findType(Class<?> role) {
97  		return typeMapper.findType(role);
98  	}
99  
100 	public Collection<URI> findSubTypes(Class<?> role, Collection<URI> rdfTypes) {
101 		findTypes(role, rdfTypes);
102 		Set<Class<?>> subset = subclasses.get(role);
103 		if (subset == null)
104 			return rdfTypes;
105 		for (Class<?> c : subset) {
106 			findSubTypes(c, rdfTypes);
107 		}
108 		return rdfTypes;
109 	}
110 
111 	public synchronized void recordRole(Class<?> role, URI type) {
112 		assert type != null;
113 		directMapper.recordRole(role, type);
114 		recordClassHierarchy(role);
115 		typeMapper.recordRole(role, type);
116 
117 		Set<Class<?>> superRoles = getSuperRoles(role);
118 		Set<Class<?>> newRoles = new HashSet<Class<?>>(superRoles.size() + 1);
119 		newRoles.addAll(superRoles);
120 		newRoles.add(role);
121 		newRoles = simpleRoleMapper.recordRoles(newRoles, type);
122 		for (Class<?> r : directMapper.getDirectRoles(type)) {
123 			addRolesInSubclasses(r, newRoles);
124 		}
125 	}
126 
127 	public void recordBaseRole(Class<?> role) {
128 		URI type = simpleRoleMapper.getBaseType();
129 		directMapper.recordRole(role, type);
130 		recordClassHierarchy(role);
131 		typeMapper.recordRole(role, type);
132 		simpleRoleMapper.recordBaseRole(role);
133 	}
134 
135 	/**
136 	 * Record the class hierarchy of the role to looks subclasses of related
137 	 * subject types.
138 	 * 
139 	 * @param role
140 	 */
141 	private void recordClassHierarchy(Class<?> role) {
142 		for (Class<?> sup : role.getInterfaces()) {
143 			Set<Class<?>> set = subclasses.get(sup);
144 			if (set == null)
145 				subclasses.put(sup, set = new HashSet<Class<?>>());
146 			if (!set.contains(role)) {
147 				set.add(role);
148 				recordClassHierarchy(sup);
149 			}
150 		}
151 	}
152 
153 	private Set<Class<?>> getSuperRoles(Class<?> role) {
154 		Class[] interfaces = role.getInterfaces();
155 		if (interfaces.length == 0)
156 			return Collections.EMPTY_SET;
157 		Set<Class<?>> superRoles = new HashSet<Class<?>>();
158 		for (Class<?> sup : interfaces) {
159 			Set<Class<?>> sr = getSuperRoles(sup);
160 			addRelatedRoles(sr, sup, superRoles);
161 		}
162 		return superRoles;
163 	}
164 
165 	private void addRolesInSubclasses(Class<?> role, Set<Class<?>> newRoles) {
166 		Set<Class<?>> subset = subclasses.get(role);
167 		if (subset == null)
168 			return; // no subclasses
169 		for (Class<?> sub : subset) {
170 			Set<Class<?>> subRoles = new HashSet<Class<?>>();
171 			subRoles = addRelatedRoles(newRoles, sub, subRoles);
172 			addRolesInSubclasses(sub, subRoles);
173 		}
174 	}
175 
176 	private Set<Class<?>> addRelatedRoles(Set<Class<?>> existing,
177 			Class<?> role, Set<Class<?>> roles) {
178 		roles.addAll(existing);
179 		Set<URI> set = directMapper.getDirectTypes(role);
180 		if (set != null) {
181 			for (URI uri : set) {
182 				simpleRoleMapper.recordRoles(existing, uri);
183 				for (Class<?> c : simpleRoleMapper.findRoles(uri)) {
184 					roles.add(c);
185 				}
186 			}
187 		}
188 		return roles;
189 	}
190 }