001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id: StatementImpl.java 20796 2007-06-19 09:52:03Z sfermigier $ 020 */ 021 022package org.nuxeo.ecm.platform.relations.api.impl; 023 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029 030import org.nuxeo.ecm.platform.relations.api.Blank; 031import org.nuxeo.ecm.platform.relations.api.Node; 032import org.nuxeo.ecm.platform.relations.api.Resource; 033import org.nuxeo.ecm.platform.relations.api.Statement; 034import org.nuxeo.ecm.platform.relations.api.Subject; 035import org.nuxeo.ecm.platform.relations.api.exceptions.InvalidPredicateException; 036import org.nuxeo.ecm.platform.relations.api.exceptions.InvalidStatementException; 037import org.nuxeo.ecm.platform.relations.api.exceptions.InvalidSubjectException; 038 039/** 040 * Statement with subject, predicate and object. 041 * 042 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 043 */ 044// TODO: make a statement handle metadata (as properties) 045public class StatementImpl implements Statement { 046 047 private static final long serialVersionUID = 1L; 048 049 protected Subject subject; 050 051 protected Resource predicate; 052 053 protected Node object; 054 055 protected Map<Resource, Node[]> properties = new HashMap<Resource, Node[]>(); 056 057 /** 058 * Constructor for NULL statement. 059 */ 060 public StatementImpl() { 061 } 062 063 /** 064 * Constructor. 065 * 066 * @param subject Resource or Blank node 067 * @param predicate Resource 068 * @param object Resource, Blank or Literal node 069 */ 070 public StatementImpl(Node subject, Node predicate, Node object) { 071 boolean validSubject = true; 072 try { 073 setSubject(subject); 074 } catch (InvalidSubjectException e) { 075 validSubject = false; 076 } 077 boolean validPredicate = true; 078 try { 079 setPredicate(predicate); 080 } catch (InvalidPredicateException e) { 081 validPredicate = false; 082 } 083 if (!validPredicate && !validSubject) { 084 throw new InvalidStatementException(); 085 } else if (!validSubject) { 086 throw new InvalidSubjectException(); 087 } else if (!validPredicate) { 088 throw new InvalidPredicateException(); 089 } 090 this.object = object; 091 } 092 093 public Node getObject() { 094 return object; 095 } 096 097 public void setObject(Node object) { 098 this.object = object; 099 } 100 101 public Resource getPredicate() { 102 return predicate; 103 } 104 105 public void setPredicate(Node predicate) { 106 if (predicate != null && !predicate.isResource()) { 107 throw new InvalidPredicateException(); 108 } 109 this.predicate = (Resource) predicate; 110 } 111 112 public Subject getSubject() { 113 return subject; 114 } 115 116 public void setSubject(Node subject) { 117 if (subject != null) { 118 if (subject instanceof Subject) { 119 this.subject = (Subject) subject; 120 } else { 121 throw new InvalidSubjectException(); 122 } 123 } 124 } 125 126 public Map<Resource, Node[]> getProperties() { 127 return properties; 128 } 129 130 public Map<String, Node[]> getStringProperties() { 131 Map<String, Node[]> stringProps = new HashMap<String, Node[]>(); 132 for (Map.Entry<Resource, Node[]> property : properties.entrySet()) { 133 stringProps.put(property.getKey().getUri(), property.getValue()); 134 } 135 return stringProps; 136 } 137 138 public Node getProperty(Resource property) { 139 // return first one found 140 Node node = null; 141 Node[] values = properties.get(property); 142 if (values != null && values.length > 0) { 143 node = values[0]; 144 } 145 return node; 146 } 147 148 public Node[] getProperties(Resource property) { 149 Node[] values = properties.get(property); 150 return values; 151 } 152 153 public void setProperties(Map<Resource, Node[]> properties) { 154 if (properties != null) { 155 for (Map.Entry<Resource, Node[]> property : properties.entrySet()) { 156 setProperties(property.getKey(), property.getValue()); 157 } 158 } else { 159 this.properties.clear(); 160 } 161 } 162 163 public void setProperty(Resource property, Node value) { 164 if (property != null && value != null) { 165 Node[] values = { value }; 166 properties.put(property, values); 167 } 168 } 169 170 public void setProperties(Resource property, Node[] values) { 171 if (property != null && values != null && values.length > 0) { 172 properties.put(property, values); 173 } 174 } 175 176 public void deleteProperties() { 177 properties.clear(); 178 } 179 180 public void deleteProperty(Resource property) { 181 properties.remove(property); 182 } 183 184 public void deleteProperty(Resource property, Node value) { 185 if (properties.containsKey(property)) { 186 List<Node> valuesList = new ArrayList<Node>(); 187 valuesList.addAll(Arrays.asList(properties.get(property))); 188 valuesList.remove(value); 189 if (valuesList.isEmpty()) { 190 properties.remove(property); 191 } else { 192 properties.put(property, valuesList.toArray(new Node[] {})); 193 } 194 } 195 } 196 197 public void deleteProperties(Resource property, Node[] values) { 198 if (properties.containsKey(property) && values != null && values.length > 0) { 199 List<Node> valuesList = new ArrayList<Node>(); 200 valuesList.addAll(Arrays.asList(properties.get(property))); 201 valuesList.removeAll(Arrays.asList(values)); 202 if (valuesList.isEmpty()) { 203 properties.remove(property); 204 } else { 205 properties.put(property, valuesList.toArray(new Node[] {})); 206 } 207 } 208 } 209 210 public void addProperties(Map<Resource, Node[]> properties) { 211 if (properties != null) { 212 for (Map.Entry<Resource, Node[]> property : properties.entrySet()) { 213 addProperties(property.getKey(), property.getValue()); 214 } 215 } 216 } 217 218 public void addProperty(Resource property, Node value) { 219 if (property != null && value != null) { 220 if (properties.containsKey(property)) { 221 List<Node> valuesList = new ArrayList<Node>(); 222 valuesList.addAll(Arrays.asList(properties.get(property))); 223 if (!valuesList.contains(value)) { 224 valuesList.add(value); 225 properties.put(property, valuesList.toArray(new Node[] {})); 226 } 227 } else { 228 Node[] values = { value }; 229 properties.put(property, values); 230 } 231 } 232 } 233 234 public void addProperties(Resource property, Node[] values) { 235 if (property != null && values != null && values.length > 0) { 236 if (properties.containsKey(property)) { 237 // add only missing nodes 238 List<Node> valuesList = new ArrayList<Node>(); 239 valuesList.addAll(Arrays.asList(properties.get(property))); 240 boolean changed = false; 241 for (Node value : values) { 242 if (!valuesList.contains(value)) { 243 valuesList.add(value); 244 changed = true; 245 } 246 } 247 if (changed) { 248 properties.put(property, valuesList.toArray(new Node[] {})); 249 } 250 } else { 251 properties.put(property, values); 252 } 253 } 254 } 255 256 @Override 257 public String toString() { 258 return String.format("%s(%s, %s, %s)", getClass().getSimpleName(), subject, predicate, object); 259 } 260 261 @Override 262 public boolean equals(Object other) { 263 if (this == other) { 264 return true; 265 } 266 if (!(other instanceof StatementImpl)) { 267 return false; 268 } 269 StatementImpl otherStatement = (StatementImpl) other; 270 return subject.equals(otherStatement.subject) && predicate.equals(otherStatement.predicate) 271 && object.equals(otherStatement.object); 272 } 273 274 @Override 275 public int hashCode() { 276 int result = 17; 277 result = 17 * result + subject.hashCode(); 278 result = 17 * result + predicate.hashCode(); 279 result = 17 * result + object.hashCode(); 280 return result; 281 } 282 283 public int compareTo(Statement o) { 284 // dumb implementation, just used to compare statements lists 285 return toString().compareTo(o.toString()); 286 } 287 288 @Override 289 public Object clone() { 290 StatementImpl clone; 291 try { 292 clone = (StatementImpl) super.clone(); 293 } catch (CloneNotSupportedException e) { 294 throw new RuntimeException(e); 295 } 296 Map<Resource, Node[]> clonedProperties = new HashMap<Resource, Node[]>(); 297 for (Map.Entry<Resource, Node[]> property : properties.entrySet()) { 298 clonedProperties.put(property.getKey(), property.getValue().clone()); 299 } 300 clone.properties = clonedProperties; 301 return clone; 302 } 303 304}