001/* 002 * Copyright (c) 2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Florent Guillaume 011 */ 012package org.nuxeo.ecm.core.schema; 013 014import static org.apache.commons.lang.ObjectUtils.NULL; 015import static org.nuxeo.ecm.core.schema.types.ComplexTypeImpl.canonicalXPath; 016 017import java.io.Serializable; 018import java.util.HashMap; 019import java.util.LinkedList; 020import java.util.List; 021import java.util.Map; 022 023import org.nuxeo.ecm.core.schema.types.Schema; 024import org.nuxeo.runtime.api.Framework; 025 026/** 027 * Information about what's to be prefetched: individual properties and whole schemas. 028 */ 029public class Prefetch implements Serializable { 030 031 private static final long serialVersionUID = 1L; 032 033 /** 034 * map of prefix:name -> value 035 * <p> 036 * key can be a canonical xpath like prefix:name/0/othername 037 * <p> 038 * null values are stored as actual nulls 039 */ 040 public Map<String, Serializable> values; 041 042 /** 043 * map of schema -> list of prefix:name 044 */ 045 public Map<String, List<String>> keysBySchema; 046 047 /** 048 * map of schema -> name -> prefix:name 049 */ 050 public Map<String, Map<String, String>> keysBySchemaAndName; 051 052 public Prefetch() { 053 values = new HashMap<String, Serializable>(); 054 keysBySchema = new HashMap<String, List<String>>(); 055 keysBySchemaAndName = new HashMap<String, Map<String, String>>(); 056 } 057 058 public boolean isEmpty() { 059 return values.isEmpty(); 060 } 061 062 public void put(String prefixedName, String schemaName, String name, Serializable value) { 063 values.put(prefixedName, value); 064 if (schemaName != null) { 065 Map<String, String> keysByName = keysBySchemaAndName.get(schemaName); 066 if (keysByName == null) { 067 keysBySchemaAndName.put(schemaName, keysByName = new HashMap<String, String>()); 068 } 069 keysByName.put(name, prefixedName); 070 List<String> keys = keysBySchema.get(schemaName); 071 if (keys == null) { 072 keysBySchema.put(schemaName, keys = new LinkedList<String>()); 073 } 074 keys.add(prefixedName); 075 } 076 } 077 078 public Serializable get(String xpath) { 079 xpath = canonicalXPath(xpath); 080 if (values.containsKey(xpath)) { 081 return cloned(values.get(xpath)); 082 } 083 return NULL; 084 } 085 086 public Serializable get(String schemaName, String name) { 087 Map<String, String> keysByName = keysBySchemaAndName.get(schemaName); 088 if (keysByName != null) { 089 String prefixedName = keysByName.get(name); 090 if (prefixedName != null && values.containsKey(prefixedName)) { 091 return cloned(values.get(prefixedName)); 092 } 093 } 094 return NULL; 095 } 096 097 // make sure we return a new array 098 protected Serializable cloned(Serializable value) { 099 if (value instanceof Object[]) { 100 value = ((Object[]) value).clone(); 101 } 102 return value; 103 } 104 105 public boolean isPrefetched(String xpath) { 106 xpath = canonicalXPath(xpath); 107 return values.containsKey(xpath); 108 } 109 110 public boolean isPrefetched(String schemaName, String name) { 111 Map<String, String> keysByName = keysBySchemaAndName.get(schemaName); 112 if (keysByName == null) { 113 return false; 114 } 115 String prefixedName = keysByName.get(name); 116 if (prefixedName == null) { 117 return false; 118 } 119 return values.containsKey(prefixedName); 120 } 121 122 /** 123 * Clears the prefetches for a given schema. 124 */ 125 public void clearPrefetch(String schemaName) { 126 keysBySchemaAndName.remove(schemaName); 127 List<String> keys = keysBySchema.remove(schemaName); 128 if (keys != null) { 129 for (String prefixedName : keys) { 130 values.remove(prefixedName); 131 } 132 } 133 } 134 135 /** 136 * Gets the schema name for a given xpath. 137 * <p> 138 * The type is used to resolve non-prefixed properties. 139 * 140 * @return the schema name or {@code null} 141 */ 142 public String getXPathSchema(String xpath, DocumentType type) { 143 xpath = canonicalXPath(xpath); 144 int i = xpath.indexOf('/'); 145 String prop = i == -1 ? xpath : xpath.substring(0, i); 146 int p = prop.indexOf(':'); 147 if (p == -1) { 148 for (Schema schema : type.getSchemas()) { 149 if (schema.hasField(prop)) { 150 return schema.getName(); 151 } 152 } 153 return null; 154 } else { 155 String prefix = prop.substring(0, p); 156 SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class); 157 Schema schema = schemaManager.getSchemaFromPrefix(prefix); 158 if (schema == null) { 159 schema = schemaManager.getSchema(prefix); 160 } 161 return schema == null ? null : schema.getName(); 162 } 163 } 164 165}