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