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