001/* 002 * (C) Copyright 2006-2018 Nuxeo (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 * Thomas Roger 018 * Dragos Mihalache 019 * Florent Guillaume 020 */ 021package org.nuxeo.ecm.core.api.impl; 022 023import static org.nuxeo.ecm.core.schema.types.ComplexTypeImpl.canonicalXPath; 024 025import java.io.Serializable; 026import java.util.Arrays; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.HashMap; 030import java.util.HashSet; 031import java.util.List; 032import java.util.Map; 033import java.util.Set; 034 035import org.nuxeo.common.utils.Path; 036import org.nuxeo.ecm.core.api.CoreSession; 037import org.nuxeo.ecm.core.api.DataModel; 038import org.nuxeo.ecm.core.api.DocumentModel; 039import org.nuxeo.ecm.core.api.DocumentRef; 040import org.nuxeo.ecm.core.api.LifeCycleConstants; 041import org.nuxeo.ecm.core.api.Lock; 042import org.nuxeo.ecm.core.api.PathRef; 043import org.nuxeo.ecm.core.api.PropertyException; 044import org.nuxeo.ecm.core.api.VersioningOption; 045import org.nuxeo.ecm.core.api.model.DocumentPart; 046import org.nuxeo.ecm.core.api.model.Property; 047import org.nuxeo.ecm.core.api.model.PropertyNotFoundException; 048import org.nuxeo.ecm.core.api.model.PropertyVisitor; 049import org.nuxeo.ecm.core.api.model.impl.DocumentPartImpl; 050import org.nuxeo.ecm.core.api.model.resolver.DocumentPropertyObjectResolverImpl; 051import org.nuxeo.ecm.core.api.model.resolver.PropertyObjectResolver; 052import org.nuxeo.ecm.core.api.security.ACP; 053import org.nuxeo.ecm.core.schema.DocumentType; 054import org.nuxeo.ecm.core.schema.SchemaManager; 055import org.nuxeo.ecm.core.schema.types.Schema; 056import org.nuxeo.runtime.api.Framework; 057 058/** 059 * A DocumentModel that can have any schema and is not made persistent by itself. A mockup to keep arbitrary schema 060 * data. 061 */ 062public class SimpleDocumentModel implements DocumentModel { 063 064 private static final long serialVersionUID = 1L; 065 066 protected final boolean anySchema; 067 068 protected final Map<String, DataModel> dataModels = new HashMap<>(); 069 070 protected Set<String> schemas; 071 072 protected final Map<String, Serializable> contextData = new HashMap<>(); 073 074 protected Path path; 075 076 protected String type; 077 078 public SimpleDocumentModel(List<String> schemas) { 079 this.schemas = new HashSet<>(); 080 anySchema = false; 081 SchemaManager schemaManager = Framework.getService(SchemaManager.class); 082 for (String schema : schemas) { 083 Schema s = schemaManager.getSchema(schema); 084 DocumentPart part = new DocumentPartImpl(s); 085 dataModels.put(schema, new DataModelImpl(part)); 086 this.schemas.add(schema); 087 } 088 } 089 090 public SimpleDocumentModel(String... schemas) { 091 this(Arrays.asList(schemas)); 092 } 093 094 public SimpleDocumentModel() { 095 schemas = new HashSet<>(); 096 anySchema = true; 097 } 098 099 protected DataModel getDataModelInternal(String schema) { 100 DataModel dm = dataModels.get(schema); 101 if (dm == null && anySchema) { 102 SchemaManager schemaManager = Framework.getService(SchemaManager.class); 103 Schema s = schemaManager.getSchema(schema); 104 DocumentPart part = new DocumentPartImpl(s); 105 dm = new DataModelImpl(part); 106 dataModels.put(schema, dm); 107 schemas.add(schema); 108 } 109 return dm; 110 } 111 112 @Override 113 public String[] getSchemas() { 114 Set<String> keys = dataModels.keySet(); 115 return keys.toArray(new String[keys.size()]); 116 } 117 118 @Override 119 public Object getProperty(String schemaName, String name) { 120 DataModel dm = getDataModelInternal(schemaName); 121 return dm != null ? dm.getData(name) : null; 122 } 123 124 @Override 125 public Property getPropertyObject(String schema, String name) { 126 DocumentPart part = getPart(schema); 127 return part == null ? null : part.get(name); 128 } 129 130 @Override 131 public void setProperty(String schemaName, String name, Object value) { 132 if (name.contains(":")) { 133 name = name.substring(name.indexOf(":"), name.length()); 134 } 135 getDataModelInternal(schemaName).setData(name, value); 136 } 137 138 @Override 139 public Map<String, Object> getProperties(String schemaName) { 140 return getDataModelInternal(schemaName).getMap(); 141 } 142 143 @Override 144 public void setProperties(String schemaName, Map<String, Object> data) { 145 DataModel dm = getDataModelInternal(schemaName); 146 dm.setMap(data); 147 // force dirty for updated properties 148 for (String field : data.keySet()) { 149 dm.setDirty(field); 150 } 151 } 152 153 @Override 154 public Map<String, Serializable> getContextData() { 155 return contextData; 156 } 157 158 @Override 159 public Serializable getContextData(String key) { 160 return contextData.get(key); 161 } 162 163 @Override 164 public void putContextData(String key, Serializable value) { 165 contextData.put(key, value); 166 } 167 168 @Override 169 public void copyContextData(DocumentModel otherDocument) { 170 contextData.putAll(otherDocument.getContextData()); 171 } 172 173 @Override 174 public Property getProperty(String xpath) throws PropertyException { 175 if (xpath == null) { 176 throw new PropertyNotFoundException("null", "Invalid null xpath"); 177 } 178 String cxpath = canonicalXPath(xpath); 179 if (cxpath.isEmpty()) { 180 throw new PropertyNotFoundException(xpath, "Schema not specified"); 181 } 182 String schemaName = DocumentModelImpl.getXPathSchemaName(cxpath, schemas, null); 183 if (schemaName == null) { 184 if (cxpath.indexOf(':') != -1) { 185 throw new PropertyNotFoundException(xpath, "No such schema"); 186 } else { 187 throw new PropertyNotFoundException(xpath); 188 } 189 190 } 191 DocumentPart part = getPart(schemaName); 192 if (part == null) { 193 throw new PropertyNotFoundException(xpath); 194 } 195 // cut prefix 196 String partPath = cxpath.substring(cxpath.indexOf(':') + 1); 197 try { 198 Property property = part.resolvePath(partPath); 199 // force dirty for updated properties 200 property.setForceDirty(true); 201 return property; 202 } catch (PropertyNotFoundException e) { 203 throw new PropertyNotFoundException(xpath, e.getDetail()); 204 } 205 } 206 207 @Override 208 public Serializable getPropertyValue(String xpath) throws PropertyException { 209 return getProperty(xpath).getValue(); 210 } 211 212 @Override 213 public void setPropertyValue(String xpath, Serializable value) { 214 getProperty(xpath).setValue(value); 215 } 216 217 @Override 218 public DocumentType getDocumentType() { 219 throw new UnsupportedOperationException(); 220 } 221 222 @Override 223 public String getSessionId() { 224 throw new UnsupportedOperationException(); 225 } 226 227 @Override 228 public CoreSession getCoreSession() { 229 throw new UnsupportedOperationException(); 230 } 231 232 @Override 233 public void detach(boolean loadAll) { 234 } 235 236 @Override 237 public void attach(String sid) { 238 } 239 240 @Override 241 public DocumentRef getRef() { 242 throw new UnsupportedOperationException(); 243 } 244 245 @Override 246 public DocumentRef getParentRef() { 247 if (path == null) { 248 return null; 249 } 250 if (!path.isAbsolute()) { 251 return null; 252 } 253 return new PathRef(path.removeLastSegments(1).toString()); 254 } 255 256 @Override 257 public String getId() { 258 throw new UnsupportedOperationException(); 259 } 260 261 @Override 262 public String getName() { 263 return path == null ? null : path.lastSegment(); 264 } 265 266 @Override 267 public Long getPos() { 268 return null; 269 } 270 271 @Override 272 public String getPathAsString() { 273 return path == null ? null : path.toString(); 274 } 275 276 @Override 277 public Path getPath() { 278 return path; 279 } 280 281 @Override 282 public String getTitle() { 283 throw new UnsupportedOperationException(); 284 } 285 286 @Override 287 public String getType() { 288 return type; 289 } 290 291 public void setType(String type) { 292 this.type = type; 293 } 294 295 @Override 296 public Set<String> getFacets() { 297 throw new UnsupportedOperationException(); 298 } 299 300 @Override 301 @Deprecated 302 public Collection<DataModel> getDataModelsCollection() { 303 throw new UnsupportedOperationException(); 304 } 305 306 @Override 307 @Deprecated 308 public Map<String, DataModel> getDataModels() { 309 return dataModels; 310 } 311 312 @Override 313 @Deprecated 314 public DataModel getDataModel(String schema) { 315 return getDataModelInternal(schema); 316 } 317 318 @Override 319 public void setPathInfo(String parentPath, String name) { 320 path = new Path(parentPath == null ? name : parentPath + '/' + name); 321 } 322 323 @Override 324 public boolean isLocked() { 325 throw new UnsupportedOperationException(); 326 } 327 328 @Override 329 public Lock setLock() { 330 throw new UnsupportedOperationException(); 331 } 332 333 @Override 334 public Lock getLockInfo() { 335 throw new UnsupportedOperationException(); 336 } 337 338 @Override 339 public Lock removeLock() { 340 throw new UnsupportedOperationException(); 341 } 342 343 @Override 344 public ACP getACP() { 345 throw new UnsupportedOperationException(); 346 } 347 348 @Override 349 public void setACP(ACP acp, boolean overwrite) { 350 throw new UnsupportedOperationException(); 351 } 352 353 @Override 354 public boolean hasSchema(String schema) { 355 throw new UnsupportedOperationException(); 356 } 357 358 @Override 359 public boolean hasFacet(String facet) { 360 throw new UnsupportedOperationException(); 361 } 362 363 @Override 364 public boolean addFacet(String facet) { 365 throw new UnsupportedOperationException(); 366 } 367 368 @Override 369 public boolean removeFacet(String facet) { 370 throw new UnsupportedOperationException(); 371 } 372 373 @Override 374 public boolean isTrashed() { 375 return LifeCycleConstants.DELETED_STATE.equals(getCurrentLifeCycleState()); 376 } 377 378 @Override 379 public boolean isFolder() { 380 throw new UnsupportedOperationException(); 381 } 382 383 @Override 384 public boolean isVersionable() { 385 throw new UnsupportedOperationException(); 386 } 387 388 @Override 389 public boolean isDownloadable() { 390 throw new UnsupportedOperationException(); 391 } 392 393 @Override 394 public boolean isVersion() { 395 throw new UnsupportedOperationException(); 396 } 397 398 @Override 399 public boolean isProxy() { 400 throw new UnsupportedOperationException(); 401 } 402 403 @Override 404 public boolean isImmutable() { 405 throw new UnsupportedOperationException(); 406 } 407 408 @Override 409 public boolean isDirty() { 410 throw new UnsupportedOperationException(); 411 } 412 413 @Override 414 public void accept(PropertyVisitor visitor, Object arg) { 415 throw new UnsupportedOperationException(); 416 } 417 418 @Override 419 public <T> T getAdapter(Class<T> itf) { 420 throw new UnsupportedOperationException(); 421 } 422 423 @Override 424 public <T> T getAdapter(Class<T> itf, boolean refreshCache) { 425 throw new UnsupportedOperationException(); 426 } 427 428 @Override 429 public String getCurrentLifeCycleState() { 430 throw new UnsupportedOperationException(); 431 } 432 433 @Override 434 public String getLifeCyclePolicy() { 435 throw new UnsupportedOperationException(); 436 } 437 438 @Override 439 public boolean followTransition(String transition) { 440 throw new UnsupportedOperationException(); 441 } 442 443 @Override 444 public Collection<String> getAllowedStateTransitions() { 445 throw new UnsupportedOperationException(); 446 } 447 448 @Override 449 public void copyContent(DocumentModel sourceDoc) { 450 throw new UnsupportedOperationException(); 451 } 452 453 @Override 454 public String getRepositoryName() { 455 throw new UnsupportedOperationException(); 456 } 457 458 @Override 459 public String getCacheKey() { 460 throw new UnsupportedOperationException(); 461 } 462 463 @Override 464 public String getSourceId() { 465 throw new UnsupportedOperationException(); 466 } 467 468 @Override 469 public String getVersionLabel() { 470 throw new UnsupportedOperationException(); 471 } 472 473 @Override 474 public String getCheckinComment() { 475 throw new UnsupportedOperationException(); 476 } 477 478 @Override 479 public boolean isPrefetched(String xpath) { 480 return false; 481 } 482 483 @Override 484 public boolean isPrefetched(String schemaName, String name) { 485 return false; 486 } 487 488 @Override 489 public void prefetchCurrentLifecycleState(String lifecycle) { 490 throw new UnsupportedOperationException(); 491 } 492 493 @Override 494 public void prefetchLifeCyclePolicy(String lifeCyclePolicy) { 495 throw new UnsupportedOperationException(); 496 } 497 498 @Override 499 public boolean isLifeCycleLoaded() { 500 throw new UnsupportedOperationException(); 501 } 502 503 @Override 504 public <T extends Serializable> T getSystemProp(String systemProperty, Class<T> type) { 505 throw new UnsupportedOperationException(); 506 } 507 508 @Override 509 @Deprecated 510 public DocumentPart getPart(String schema) { 511 DataModel dm = getDataModel(schema); 512 if (dm != null) { 513 return ((DataModelImpl) dm).getDocumentPart(); 514 } 515 return null; 516 } 517 518 @Override 519 @Deprecated 520 public DocumentPart[] getParts() { 521 throw new UnsupportedOperationException(); 522 } 523 524 @Override 525 public Collection<Property> getPropertyObjects(String schema) { 526 DocumentPart part = getPart(schema); 527 return part == null ? Collections.emptyList() : part.getChildren(); 528 } 529 530 @Override 531 public void reset() { 532 throw new UnsupportedOperationException(); 533 } 534 535 @Override 536 public void refresh(int refreshFlags, String[] schemas) { 537 throw new UnsupportedOperationException(); 538 } 539 540 @Override 541 public void refresh() { 542 throw new UnsupportedOperationException(); 543 } 544 545 @Override 546 public DocumentModel clone() throws CloneNotSupportedException { 547 throw new UnsupportedOperationException(); 548 } 549 550 @Override 551 public boolean isCheckedOut() { 552 throw new UnsupportedOperationException(); 553 } 554 555 @Override 556 public void checkOut() { 557 throw new UnsupportedOperationException(); 558 } 559 560 @Override 561 public DocumentRef checkIn(VersioningOption option, String description) { 562 throw new UnsupportedOperationException(); 563 } 564 565 @Override 566 public String getVersionSeriesId() { 567 throw new UnsupportedOperationException(); 568 } 569 570 @Override 571 public boolean isLatestVersion() { 572 return false; 573 } 574 575 @Override 576 public boolean isMajorVersion() { 577 return false; 578 } 579 580 @Override 581 public boolean isLatestMajorVersion() { 582 return false; 583 } 584 585 @Override 586 public boolean isVersionSeriesCheckedOut() { 587 return true; 588 } 589 590 @Override 591 public String getChangeToken() { 592 return null; 593 } 594 595 @Override 596 public Map<String, String> getBinaryFulltext() { 597 return null; 598 } 599 600 @Override 601 public PropertyObjectResolver getObjectResolver(String xpath) { 602 return DocumentPropertyObjectResolverImpl.create(this, xpath); 603 } 604 605}