/*package*/ M2ModelDefinition( M2Model model, NamespacePrefixResolver resolver, DictionaryDAO dictionaryDAO) { this.name = QName.createQName(model.getName(), resolver); this.model = model; this.analyserResourceBundleName = model.getAnalyserResourceBundleName(); this.dictionaryDAO = dictionaryDAO; }
/** * Construct compiled definitions * * @param model model definition * @param namespaceDAO namespace DAO */ private void constructDefinitions(M2Model model, NamespaceDAO namespaceDAO) { NamespacePrefixResolver localPrefixes = createLocalPrefixResolver(model, namespaceDAO); // Construct Model Definition modelDefinition = new M2ModelDefinition(model, localPrefixes); // Construct Property Types for (M2DataType propType : model.getPropertyTypes()) { M2DataTypeDefinition def = new M2DataTypeDefinition(modelDefinition, propType, localPrefixes); if (dataTypes.containsKey(def.getName())) { throw new DictionaryException( "Found duplicate property type definition " + propType.getName()); } dataTypes.put(def.getName(), def); } // Construct Type Definitions for (M2Type type : model.getTypes()) { M2TypeDefinition def = new M2TypeDefinition(modelDefinition, type, localPrefixes, properties, associations); if (classes.containsKey(def.getName())) { throw new DictionaryException( "Found duplicate class definition " + type.getName() + " (a type)"); } classes.put(def.getName(), def); types.put(def.getName(), def); } // Construct Aspect Definitions for (M2Aspect aspect : model.getAspects()) { M2AspectDefinition def = new M2AspectDefinition(modelDefinition, aspect, localPrefixes, properties, associations); if (classes.containsKey(def.getName())) { throw new DictionaryException( "Found duplicate class definition " + aspect.getName() + " (an aspect)"); } classes.put(def.getName(), def); aspects.put(def.getName(), def); } // Construct Constraint Definitions for (M2Constraint constraint : model.getConstraints()) { M2ConstraintDefinition def = new M2ConstraintDefinition(modelDefinition, null, constraint, localPrefixes); QName qname = def.getName(); if (constraints.containsKey(qname)) { throw new DictionaryException( "Found duplicate constraint definition " + constraint.getName() + " (an aspect)"); } constraints.put(qname, def); } }
/* (non-Javadoc) * @see org.alfresco.service.cmr.dictionary.ModelDefinition#getNamespaces() */ public Collection<NamespaceDefinition> getNamespaces() { List<NamespaceDefinition> namespaces = new ArrayList<NamespaceDefinition>(); for (M2Namespace namespace : model.getNamespaces()) { namespaces.add(new M2NamespaceDefinition(this, namespace.getUri(), namespace.getPrefix())); } return namespaces; }
/* (non-Javadoc) * @see org.alfresco.repo.dictionary.ModelDefinition#getDescription() */ public String getDescription() { String value = M2Label.getLabel(this, null, null, "description"); if (value == null) { value = model.getDescription(); } return value; }
/** * Create a M2Model from a dictionary model node * * @param nodeRef the dictionary model node reference * @return the M2Model */ public M2Model createM2Model(NodeRef nodeRef) { M2Model model = null; ContentReader contentReader = this.contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); if (contentReader != null) { if (contentReader instanceof EmptyContentReader) { // belts-and-braces logger.error("Failed to create model (due to EmptyContentReader): " + nodeRef); } else { InputStream is = null; try { is = contentReader.getContentInputStream(); model = M2Model.createModel(is); } finally { if (is != null) { try { is.close(); } catch (IOException e) { logger.error("Failed to close input stream for " + nodeRef); } } } } } // TODO should we inactivate the model node and put the error somewhere?? return model; }
/* (non-Javadoc) * @see org.alfresco.service.cmr.dictionary.ModelDefinition#isNamespaceImported(java.lang.String) */ public boolean isNamespaceImported(String uri) { for (M2Namespace namespace : model.getImports()) { if (namespace.getUri().equals(uri)) { return true; } } return false; }
/** * Loads a model (and its dependents) if it does not exist in the list of loaded models. * * @param modelMap a map of the models to be loaded * @param loadedModels the list of models already loaded * @param model the model to try and load */ private void loadModel( Map<String, DynamicModelInfo> modelMap, List<String> loadedModels, M2Model model, RepositoryLocation modelLocation) { String modelName = model.getName(); if (loadedModels.contains(modelName) == false) { for (M2Namespace importNamespace : model.getImports()) { DynamicModelInfo entry = modelMap.get(importNamespace.getUri()); if (entry != null) { RepositoryLocation importedLocation = entry.location; M2Model importedModel = entry.model; // Ensure that the imported model is loaded first loadModel(modelMap, loadedModels, importedModel, importedLocation); } // else we can assume that the imported model is already loaded, if this not the case then // an error will be raised during compilation } try { if (logger.isDebugEnabled()) { logger.debug( "Loading model: " + modelName + " (from [" + modelLocation.getStoreRef() + "]" + modelLocation.getPath() + ")"); } dictionaryDAO.putModel(model); loadedModels.add(modelName); } catch (AlfrescoRuntimeException e) { // note: skip with warning - to allow server to start, and hence allow the possibility of // fixing the broken model(s) logger.warn("Failed to load model '" + modelName + "' : " + e); } } }
/** * Create a local namespace prefix resolver containing the namespaces defined and imported in the * model * * @param model model definition * @param namespaceDAO namespace DAO * @return the local namespace prefix resolver */ private NamespacePrefixResolver createLocalPrefixResolver( M2Model model, NamespaceDAO namespaceDAO) { // Retrieve set of existing URIs for validation purposes Collection<String> uris = namespaceDAO.getURIs(); // Create a namespace prefix resolver based on imported and defined // namespaces within the model DynamicNamespacePrefixResolver prefixResolver = new DynamicNamespacePrefixResolver(null); for (M2Namespace imported : model.getImports()) { String uri = imported.getUri(); if (!uris.contains(uri)) { throw new NamespaceException( "URI " + uri + " cannot be imported as it is not defined (with prefix " + imported.getPrefix()); } prefixResolver.registerNamespace(imported.getPrefix(), uri); } for (M2Namespace defined : model.getNamespaces()) { prefixResolver.registerNamespace(defined.getPrefix(), defined.getUri()); } return prefixResolver; }
/** * Construct * * @param model model definition * @param dictionaryDAO dictionary DAO * @param namespaceDAO namespace DAO */ /*package*/ CompiledModel(M2Model model, DictionaryDAO dictionaryDAO, NamespaceDAO namespaceDAO) { try { // Phase 1: Construct model definitions from model entries // resolving qualified names this.model = model; constructDefinitions(model, namespaceDAO); // Phase 2: Resolve dependencies between model definitions ModelQuery query = new DelegateModelQuery(this, dictionaryDAO); resolveDependencies(query, namespaceDAO); // Phase 3: Resolve inheritance of values within class hierachy NamespacePrefixResolver localPrefixes = createLocalPrefixResolver(model, namespaceDAO); resolveInheritance(query, localPrefixes, constraints); // Phase 4: Resolve constraint dependencies for (ConstraintDefinition def : constraints.values()) { ((M2ConstraintDefinition) def).resolveDependencies(query); } } catch (Exception e) { throw new DictionaryException("Failed to compile model " + model.getName(), e); } }
/* (non-Javadoc) * @see org.alfresco.repo.dictionary.ModelDefinition#getVersion() */ public String getVersion() { return model.getVersion(); }
/* (non-Javadoc) * @see org.alfresco.repo.dictionary.ModelDefinition#getPublishedDate() */ public Date getPublishedDate() { return model.getPublishedDate(); }
/* (non-Javadoc) * @see org.alfresco.repo.dictionary.ModelDefinition#getAuthor() */ public String getAuthor() { return model.getAuthor(); }
public long getChecksum(XMLBindingType bindingType) { return model.getChecksum(bindingType); }
public void toXML(XMLBindingType bindingType, OutputStream xml) { model.toXML(bindingType, xml); }
/** Perform the actual repository access, checking for the existence of a valid transaction */ private void onDictionaryInitInTxn() { if (AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_NONE) { throw new IllegalStateException( "The Repository-based dictionary initialization has to be done in the context of a transaction."); } long startTime = System.currentTimeMillis(); if (logger.isTraceEnabled()) { String tenantDomain = tenantAdminService.getCurrentUserDomain(); logger.trace( "onDictionaryInit: [" + Thread.currentThread() + "]" + (tenantDomain.equals(TenantService.DEFAULT_DOMAIN) ? "" : " (Tenant: " + tenantDomain + ")")); } Collection<QName> modelsBefore = dictionaryDAO.getModels(true); // note: re-entrant int modelsBeforeCnt = (modelsBefore != null ? modelsBefore.size() : 0); List<String> loadedModels = new ArrayList<String>(); if (this.repositoryModelsLocations != null) { // URI to model map Map<String, DynamicModelInfo> modelMap = new HashMap<String, DynamicModelInfo>(); if (logger.isTraceEnabled()) { logger.trace("onDictionaryInit: locations=" + this.repositoryModelsLocations); } // Register the models found in the repository for (RepositoryLocation repositoryLocation : this.repositoryModelsLocations) { StoreRef storeRef = repositoryLocation.getStoreRef(); if (!nodeService.exists(storeRef)) { logger.info("StoreRef '" + storeRef + "' does not exist"); continue; // skip this location } List<NodeRef> nodeRefs = null; if (repositoryLocation.getQueryLanguage().equals(RepositoryLocation.LANGUAGE_PATH)) { nodeRefs = getNodes(storeRef, repositoryLocation, ContentModel.TYPE_DICTIONARY_MODEL); if (nodeRefs.size() > 0) { for (NodeRef dictionaryModel : nodeRefs) { try { // Ignore if the node is a working copy or archived, or if its inactive if (!(nodeService.hasAspect(dictionaryModel, ContentModel.ASPECT_WORKING_COPY) || nodeService.hasAspect(dictionaryModel, ContentModel.ASPECT_ARCHIVED))) { Boolean isActive = (Boolean) nodeService.getProperty(dictionaryModel, ContentModel.PROP_MODEL_ACTIVE); if ((isActive != null) && (isActive.booleanValue() == true)) { M2Model model = createM2Model(dictionaryModel); if (model != null) { if (logger.isTraceEnabled()) { logger.trace( "onDictionaryInit: " + model.getName() + " (" + dictionaryModel + ")"); } for (M2Namespace namespace : model.getNamespaces()) { modelMap.put( namespace.getUri(), new DynamicModelInfo(repositoryLocation, model, dictionaryModel)); } } } } } catch (InvalidNodeRefException inre) { // ignore - model no longer exists if (logger.isDebugEnabled()) { logger.debug("onDictionaryInit: " + inre + " (assume concurrently deleted)"); } continue; } } } } else { logger.error( "Unsupported query language for models location: " + repositoryLocation.getQueryLanguage()); } } // Load the models ensuring that they are loaded in the correct order for (Map.Entry<String, DynamicModelInfo> entry : modelMap.entrySet()) { RepositoryLocation importedLocation = entry.getValue().location; M2Model importedModel = entry.getValue().model; loadModel(modelMap, loadedModels, importedModel, importedLocation); notifyDynamicModelLoaded(entry.getValue()); } } Collection<QName> modelsAfter = dictionaryDAO.getModels(true); int modelsAfterCnt = (modelsAfter != null ? modelsAfter.size() : 0); if (logger.isDebugEnabled()) { String tenantDomain = tenantAdminService.getCurrentUserDomain(); logger.debug( "Model count: before=" + modelsBeforeCnt + ", load/update=" + loadedModels.size() + ", after=" + modelsAfterCnt + " in " + (System.currentTimeMillis() - startTime) + " msecs [" + Thread.currentThread() + "] " + (tenantDomain.equals(TenantService.DEFAULT_DOMAIN) ? "" : " (Tenant: " + tenantDomain + ")")); } }