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.lang.reflect.AnnotatedElement;
32  import java.util.ArrayList;
33  import java.util.Arrays;
34  import java.util.Collection;
35  import java.util.List;
36  import java.util.Map;
37  import java.util.concurrent.ConcurrentHashMap;
38  import java.util.concurrent.CopyOnWriteArrayList;
39  
40  import org.openrdf.elmo.RdfTypeFactory;
41  import org.openrdf.elmo.annotations.complementOf;
42  import org.openrdf.elmo.annotations.intersectionOf;
43  import org.openrdf.elmo.annotations.oneOf;
44  
45  /**
46   * Tracks recorded roles and maps them to their subject type.
47   * 
48   * @author James Leigh
49   * 
50   */
51  public class ComplexMapper<URI> {
52  	private HierarchicalRoleMapper<URI> roleMapper;
53  
54  	private RdfTypeFactory<URI> vf;
55  
56  	private Map<Class<?>, AnnotatedElement> complements;
57  
58  	private Map<Class<?>, AnnotatedElement> intersections;
59  
60  	private Map<URI, List<Class<?>>> instances;
61  
62  	public ComplexMapper(HierarchicalRoleMapper<URI> roleMapper) {
63  		this.roleMapper = roleMapper;
64  		complements = new ConcurrentHashMap<Class<?>, AnnotatedElement>();
65  		intersections = new ConcurrentHashMap<Class<?>, AnnotatedElement>();
66  		instances = new ConcurrentHashMap<URI, List<Class<?>>>(256);
67  	}
68  
69  	public void setRdfTypeFactory(RdfTypeFactory<URI> vf) {
70  		this.vf = vf;
71  		roleMapper.setRdfTypeFactory(vf);
72  	}
73  
74  	public Collection<URI> findSubTypes(Class<?> role, Collection<URI> rdfTypes) {
75  		return roleMapper.findSubTypes(role, rdfTypes);
76  	}
77  
78  	public URI findType(Class<?> role) {
79  		return roleMapper.findType(role);
80  	}
81  
82  	public Collection<URI> findTypes(Class<?> javaClass, Collection<URI> rdfTypes) {
83  		return roleMapper.findTypes(javaClass, rdfTypes);
84  	}
85  
86  	public boolean isTypeRecorded(URI type) {
87  		return roleMapper.isTypeRecorded(type);
88  	}
89  
90  	public boolean isIndividualRolesPresent(URI instance) {
91  		return !instances.isEmpty() && instances.containsKey(instance);
92  	}
93  
94  	public Collection<Class<?>> findIndividualRoles(URI instance,
95  			Collection<Class<?>> classes) {
96  		List<Class<?>> list = instances.get(instance);
97  		if (list != null) {
98  			classes.addAll(list);
99  		}
100 		return classes;
101 	}
102 
103 	public Class<?>[] findBaseRoles() {
104 		return findRoles(null);
105 	}
106 
107 	public Class<?>[] findRoles(URI type) {
108 		Class<?>[] classes;
109 		if (type == null) {
110 			classes = roleMapper.findBaseRoles();
111 		} else {
112 			classes = roleMapper.findRoles(type);
113 		}
114 		if (complements.isEmpty())
115 			return classes;
116 		int size = classes.length + complements.size() + intersections.size();
117 		List<Class<?>> result = new ArrayList<Class<?>>(size);
118 		result.addAll(Arrays.asList(classes));
119 		addIntersectionsAndComplements(result);
120 		if (result.size() == classes.length)
121 			return classes;
122 		return result.toArray(new Class<?>[result.size()]);
123 	}
124 
125 	public Collection<Class<?>> findRoles(Collection<URI> types,
126 			Collection<Class<?>> classes) {
127 		Collection<Class<?>> roles = roleMapper.findRoles(types, classes);
128 		addIntersectionsAndComplements(roles);
129 		return roles;
130 	}
131 
132 	public void recordRole(Class<?> role, URI rdfType) {
133 		roleMapper.recordRole(role, rdfType);
134 	}
135 
136 	public void recordBaseRole(Class<?> role) {
137 		roleMapper.recordBaseRole(role);
138 	}
139 
140 	public synchronized void recordRole(Class<?> role, AnnotatedElement elm) {
141 		if (elm.isAnnotationPresent(complementOf.class)) {
142 			complements.put(role, elm);
143 		}
144 		if (elm.isAnnotationPresent(intersectionOf.class)) {
145 			intersections.put(role, elm);
146 		}
147 		if (elm.isAnnotationPresent(oneOf.class)) {
148 			oneOf ann = elm.getAnnotation(oneOf.class);
149 			for (String instance : ann.value()) {
150 				URI uri = vf.createRdfType(instance);
151 				List<Class<?>> list = instances.get(uri);
152 				if (list == null) {
153 					list = new CopyOnWriteArrayList<Class<?>>();
154 					instances.put(uri, list);
155 				}
156 				list.add(role);
157 			}
158 		}
159 	}
160 
161 	private void addIntersectionsAndComplements(Collection<Class<?>> roles) {
162 		for (Map.Entry<Class<?>, AnnotatedElement> e : intersections.entrySet()) {
163 			Class<?> inter = e.getKey();
164 			AnnotatedElement elm = e.getValue();
165 			Class<?>[] of = elm.getAnnotation(intersectionOf.class).value();
166 			if (!roles.contains(inter) && intersects(roles, of))
167 				roles.add(inter);
168 		}
169 		boolean complementAdded = false;
170 		for (Map.Entry<Class<?>, AnnotatedElement> e : complements.entrySet()) {
171 			Class<?> comp = e.getKey();
172 			AnnotatedElement elm = e.getValue();
173 			Class<?> of = elm.getAnnotation(complementOf.class).value();
174 			if (!roles.contains(comp) && !contains(roles, of)) {
175 				complementAdded = true;
176 				roles.add(comp);
177 			}
178 		}
179 		if (complementAdded) {
180 			for (Map.Entry e : intersections.entrySet()) {
181 				Class<?> inter = (Class<?>) e.getKey();
182 				AnnotatedElement elm = (AnnotatedElement) e.getValue();
183 				Class<?>[] of = elm.getAnnotation(intersectionOf.class).value();
184 				if (!roles.contains(inter) && intersects(roles, of))
185 					roles.add(inter);
186 			}
187 		}
188 	}
189 
190 	private boolean intersects(Collection<Class<?>> roles, Class<?>[] ofs) {
191 		for (Class<?> of : ofs) {
192 			if (!contains(roles, of))
193 				return false;
194 		}
195 		return true;
196 	}
197 
198 	private boolean contains(Collection<Class<?>> roles, Class<?> of) {
199 		for (Class<?> type : roles) {
200 			if (of.isAssignableFrom(type))
201 				return true;
202 		}
203 		return false;
204 	}
205 }