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