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.Node; 031import org.nuxeo.ecm.platform.relations.api.Resource; 032import org.nuxeo.ecm.platform.relations.api.Statement; 033import org.nuxeo.ecm.platform.relations.api.Subject; 034import org.nuxeo.ecm.platform.relations.api.exceptions.InvalidPredicateException; 035import org.nuxeo.ecm.platform.relations.api.exceptions.InvalidStatementException; 036import org.nuxeo.ecm.platform.relations.api.exceptions.InvalidSubjectException; 037 038/** 039 * Statement with subject, predicate and object. 040 * 041 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 042 */ 043// TODO: make a statement handle metadata (as properties) 044public class StatementImpl implements Statement { 045 046 private static final long serialVersionUID = 1L; 047 048 protected Subject subject; 049 050 protected Resource predicate; 051 052 protected Node object; 053 054 protected Map<Resource, Node[]> properties = new HashMap<>(); 055 056 /** 057 * Constructor for NULL statement. 058 */ 059 public StatementImpl() { 060 } 061 062 /** 063 * Constructor. 064 * 065 * @param subject Resource or Blank node 066 * @param predicate Resource 067 * @param object Resource, Blank or Literal node 068 */ 069 public StatementImpl(Node subject, Node predicate, Node object) { 070 boolean validSubject = true; 071 try { 072 setSubject(subject); 073 } catch (InvalidSubjectException e) { 074 validSubject = false; 075 } 076 boolean validPredicate = true; 077 try { 078 setPredicate(predicate); 079 } catch (InvalidPredicateException e) { 080 validPredicate = false; 081 } 082 if (!validPredicate && !validSubject) { 083 throw new InvalidStatementException(); 084 } else if (!validSubject) { 085 throw new InvalidSubjectException(); 086 } else if (!validPredicate) { 087 throw new InvalidPredicateException(); 088 } 089 this.object = object; 090 } 091 092 @Override 093 public Node getObject() { 094 return object; 095 } 096 097 @Override 098 public void setObject(Node object) { 099 this.object = object; 100 } 101 102 @Override 103 public Resource getPredicate() { 104 return predicate; 105 } 106 107 @Override 108 public void setPredicate(Node predicate) { 109 if (predicate != null && !predicate.isResource()) { 110 throw new InvalidPredicateException(); 111 } 112 this.predicate = (Resource) predicate; 113 } 114 115 @Override 116 public Subject getSubject() { 117 return subject; 118 } 119 120 @Override 121 public void setSubject(Node subject) { 122 if (subject != null) { 123 if (subject instanceof Subject) { 124 this.subject = (Subject) subject; 125 } else { 126 throw new InvalidSubjectException(); 127 } 128 } 129 } 130 131 @Override 132 public Map<Resource, Node[]> getProperties() { 133 return properties; 134 } 135 136 @Override 137 public Map<String, Node[]> getStringProperties() { 138 Map<String, Node[]> stringProps = new HashMap<>(); 139 for (Map.Entry<Resource, Node[]> property : properties.entrySet()) { 140 stringProps.put(property.getKey().getUri(), property.getValue()); 141 } 142 return stringProps; 143 } 144 145 @Override 146 public Node getProperty(Resource property) { 147 // return first one found 148 Node node = null; 149 Node[] values = properties.get(property); 150 if (values != null && values.length > 0) { 151 node = values[0]; 152 } 153 return node; 154 } 155 156 @Override 157 public Node[] getProperties(Resource property) { 158 Node[] values = properties.get(property); 159 return values; 160 } 161 162 @Override 163 public void setProperties(Map<Resource, Node[]> properties) { 164 if (properties != null) { 165 for (Map.Entry<Resource, Node[]> property : properties.entrySet()) { 166 setProperties(property.getKey(), property.getValue()); 167 } 168 } else { 169 this.properties.clear(); 170 } 171 } 172 173 @Override 174 public void setProperty(Resource property, Node value) { 175 if (property != null && value != null) { 176 Node[] values = { value }; 177 properties.put(property, values); 178 } 179 } 180 181 @Override 182 public void setProperties(Resource property, Node[] values) { 183 if (property != null && values != null && values.length > 0) { 184 properties.put(property, values); 185 } 186 } 187 188 @Override 189 public void deleteProperties() { 190 properties.clear(); 191 } 192 193 @Override 194 public void deleteProperty(Resource property) { 195 properties.remove(property); 196 } 197 198 @Override 199 public void deleteProperty(Resource property, Node value) { 200 if (properties.containsKey(property)) { 201 List<Node> valuesList = new ArrayList<>(); 202 valuesList.addAll(Arrays.asList(properties.get(property))); 203 valuesList.remove(value); 204 if (valuesList.isEmpty()) { 205 properties.remove(property); 206 } else { 207 properties.put(property, valuesList.toArray(new Node[] {})); 208 } 209 } 210 } 211 212 @Override 213 public void deleteProperties(Resource property, Node[] values) { 214 if (properties.containsKey(property) && values != null && values.length > 0) { 215 List<Node> valuesList = new ArrayList<>(); 216 valuesList.addAll(Arrays.asList(properties.get(property))); 217 valuesList.removeAll(Arrays.asList(values)); 218 if (valuesList.isEmpty()) { 219 properties.remove(property); 220 } else { 221 properties.put(property, valuesList.toArray(new Node[] {})); 222 } 223 } 224 } 225 226 @Override 227 public void addProperties(Map<Resource, Node[]> properties) { 228 if (properties != null) { 229 for (Map.Entry<Resource, Node[]> property : properties.entrySet()) { 230 addProperties(property.getKey(), property.getValue()); 231 } 232 } 233 } 234 235 @Override 236 public void addProperty(Resource property, Node value) { 237 if (property != null && value != null) { 238 if (properties.containsKey(property)) { 239 List<Node> valuesList = new ArrayList<>(); 240 valuesList.addAll(Arrays.asList(properties.get(property))); 241 if (!valuesList.contains(value)) { 242 valuesList.add(value); 243 properties.put(property, valuesList.toArray(new Node[] {})); 244 } 245 } else { 246 Node[] values = { value }; 247 properties.put(property, values); 248 } 249 } 250 } 251 252 @Override 253 public void addProperties(Resource property, Node[] values) { 254 if (property != null && values != null && values.length > 0) { 255 if (properties.containsKey(property)) { 256 // add only missing nodes 257 List<Node> valuesList = new ArrayList<>(); 258 valuesList.addAll(Arrays.asList(properties.get(property))); 259 boolean changed = false; 260 for (Node value : values) { 261 if (!valuesList.contains(value)) { 262 valuesList.add(value); 263 changed = true; 264 } 265 } 266 if (changed) { 267 properties.put(property, valuesList.toArray(new Node[] {})); 268 } 269 } else { 270 properties.put(property, values); 271 } 272 } 273 } 274 275 @Override 276 public String toString() { 277 return String.format("%s(%s, %s, %s)", getClass().getSimpleName(), subject, predicate, object); 278 } 279 280 @Override 281 public boolean equals(Object other) { 282 if (this == other) { 283 return true; 284 } 285 if (!(other instanceof StatementImpl)) { 286 return false; 287 } 288 StatementImpl otherStatement = (StatementImpl) other; 289 return subject.equals(otherStatement.subject) && predicate.equals(otherStatement.predicate) 290 && object.equals(otherStatement.object); 291 } 292 293 @Override 294 public int hashCode() { 295 int result = 17; 296 result = 17 * result + subject.hashCode(); 297 result = 17 * result + predicate.hashCode(); 298 result = 17 * result + object.hashCode(); 299 return result; 300 } 301 302 @Override 303 public int compareTo(Statement o) { 304 // dumb implementation, just used to compare statements lists 305 return toString().compareTo(o.toString()); 306 } 307 308 @Override 309 public Object clone() { 310 StatementImpl clone; 311 try { 312 clone = (StatementImpl) super.clone(); 313 } catch (CloneNotSupportedException e) { 314 throw new RuntimeException(e); 315 } 316 Map<Resource, Node[]> clonedProperties = new HashMap<>(); 317 for (Map.Entry<Resource, Node[]> property : properties.entrySet()) { 318 clonedProperties.put(property.getKey(), property.getValue().clone()); 319 } 320 clone.properties = clonedProperties; 321 return clone; 322 } 323 324}