Repository: cayenne Updated Branches: refs/heads/master d608777a9 -> 11b916f85
CAY-2336 Support for comments in Cayenne Modeler - InfoExtension Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/61985550 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/61985550 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/61985550 Branch: refs/heads/master Commit: 61985550230f529c1db5e28e856224ab99f9ecb3 Parents: d608777 Author: Nikita Timofeev <[email protected]> Authored: Tue Jul 25 15:53:56 2017 +0300 Committer: Nikita Timofeev <[email protected]> Committed: Tue Jul 25 15:53:56 2017 +0300 ---------------------------------------------------------------------- .../project/extension/info/InfoExtension.java | 52 ++++++++ .../extension/info/InfoLoaderDelegate.java | 49 +++++++ .../extension/info/InfoSaverDelegate.java | 129 +++++++++++++++++++ .../project/extension/info/ObjectInfo.java | 77 +++++++++++ .../project/extension/info/PropertyHandler.java | 113 ++++++++++++++++ 5 files changed, 420 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/61985550/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoExtension.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoExtension.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoExtension.java new file mode 100644 index 0000000..ecbf8f1 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoExtension.java @@ -0,0 +1,52 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.project.extension.info; + +import org.apache.cayenne.configuration.xml.DataChannelMetaData; +import org.apache.cayenne.di.Inject; +import org.apache.cayenne.project.Project; +import org.apache.cayenne.project.extension.LoaderDelegate; +import org.apache.cayenne.project.extension.ProjectExtension; +import org.apache.cayenne.project.extension.SaverDelegate; + +/** + * Extension that provides additional properties for project entities. + * It stores data in {@link ObjectInfo} associated with objects via {@link DataChannelMetaData}. + * Currently used by Modeler and cgen tools to provide user comments. + * + * @since 4.1 + */ +public class InfoExtension implements ProjectExtension { + + static final String NAMESPACE = "http://cayenne.apache.org/schema/" + Project.VERSION + "/info"; + + @Inject + private DataChannelMetaData metaData; + + @Override + public LoaderDelegate createLoaderDelegate() { + return new InfoLoaderDelegate(metaData); + } + + @Override + public SaverDelegate createSaverDelegate() { + return new InfoSaverDelegate(metaData); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/61985550/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoLoaderDelegate.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoLoaderDelegate.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoLoaderDelegate.java new file mode 100644 index 0000000..c7dc85b --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoLoaderDelegate.java @@ -0,0 +1,49 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.project.extension.info; + +import org.apache.cayenne.configuration.xml.DataChannelMetaData; +import org.apache.cayenne.configuration.xml.NamespaceAwareNestedTagHandler; +import org.apache.cayenne.project.extension.LoaderDelegate; + +/** + * @since 4.1 + */ +class InfoLoaderDelegate implements LoaderDelegate { + + private DataChannelMetaData metaData; + + InfoLoaderDelegate(DataChannelMetaData metaData) { + this.metaData = metaData; + } + + @Override + public String getTargetNamespace() { + return InfoExtension.NAMESPACE; + } + + @Override + public NamespaceAwareNestedTagHandler createHandler(NamespaceAwareNestedTagHandler parent, String tag) { + if(PropertyHandler.PROPERTY_TAG.equals(tag)) { + return new PropertyHandler(parent, metaData); + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/61985550/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoSaverDelegate.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoSaverDelegate.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoSaverDelegate.java new file mode 100644 index 0000000..694c52d --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/InfoSaverDelegate.java @@ -0,0 +1,129 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.project.extension.info; + +import java.util.Map; + +import org.apache.cayenne.configuration.ConfigurationNode; +import org.apache.cayenne.configuration.xml.DataChannelMetaData; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.Embeddable; +import org.apache.cayenne.map.EmbeddableAttribute; +import org.apache.cayenne.map.ObjAttribute; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; +import org.apache.cayenne.map.Procedure; +import org.apache.cayenne.map.ProcedureParameter; +import org.apache.cayenne.map.QueryDescriptor; +import org.apache.cayenne.project.extension.BaseSaverDelegate; +import org.apache.cayenne.util.Util; + +/** + * @since 4.1 + */ +class InfoSaverDelegate extends BaseSaverDelegate { + + private DataChannelMetaData metaData; + + InfoSaverDelegate(DataChannelMetaData metaData) { + this.metaData = metaData; + } + + private Void printComment(ConfigurationNode entity) { + ObjectInfo info = metaData.get(entity, ObjectInfo.class); + if(info == null) { + return null; + } + + for(Map.Entry<String, String> entry : info.getSortedValues().entrySet()) { + if(!Util.isEmptyString(entry.getValue())) { + encoder.start("info:property") + .attribute("xmlns:info", InfoExtension.NAMESPACE) + .attribute("name", entry.getKey()) + .attribute("value", entry.getValue()) + .end(); + } + } + return null; + } + + @Override + public Void visitDataMap(DataMap dataMap) { + return printComment(dataMap); + } + + @Override + public Void visitObjEntity(ObjEntity entity) { + return printComment(entity); + } + + @Override + public Void visitDbEntity(DbEntity entity) { + return printComment(entity); + } + + @Override + public Void visitEmbeddable(Embeddable embeddable) { + return printComment(embeddable); + } + + @Override + public Void visitEmbeddableAttribute(EmbeddableAttribute attribute) { + return printComment(attribute); + } + + @Override + public Void visitObjAttribute(ObjAttribute attribute) { + return printComment(attribute); + } + + @Override + public Void visitDbAttribute(DbAttribute attribute) { + return printComment(attribute); + } + + @Override + public Void visitObjRelationship(ObjRelationship relationship) { + return printComment(relationship); + } + + @Override + public Void visitDbRelationship(DbRelationship relationship) { + return printComment(relationship); + } + + @Override + public Void visitProcedure(Procedure procedure) { + return printComment(procedure); + } + + @Override + public Void visitProcedureParameter(ProcedureParameter parameter) { + return printComment(parameter); + } + + @Override + public Void visitQuery(QueryDescriptor query) { + return printComment(query); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/61985550/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/ObjectInfo.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/ObjectInfo.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/ObjectInfo.java new file mode 100644 index 0000000..c3a6449 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/ObjectInfo.java @@ -0,0 +1,77 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.project.extension.info; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.cayenne.configuration.ConfigurationNode; +import org.apache.cayenne.configuration.xml.DataChannelMetaData; + +/** + * Key-value storage for additional info associated with data map elements. + * + * @since 4.1 + */ +public class ObjectInfo { + + public static final String COMMENT = "comment"; + + private Map<String, String> infoMap = new HashMap<>(); + + public static void putToMetaData(DataChannelMetaData metaData, ConfigurationNode object, String key, String value) { + ObjectInfo info = metaData.get(object, ObjectInfo.class); + if(info == null) { + info = new ObjectInfo(); + metaData.add(object, info); + } + + info.put(key, value); + } + + public static String getFromMetaData(DataChannelMetaData metaData, ConfigurationNode object, String key) { + ObjectInfo info = metaData.get(object, ObjectInfo.class); + if(info == null) { + return null; + } + + return info.get(key); + } + + /** + * Package private constructor, use {@link ObjectInfo#putToMetaData(DataChannelMetaData, ConfigurationNode, String, String)} + * to create instance. + */ + ObjectInfo() { + } + + public String put(String key, String value) { + return infoMap.put(key, value); + } + + public String get(String key) { + return infoMap.get(key); + } + + Map<String, String> getSortedValues() { + return new TreeMap<>(infoMap); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/61985550/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/PropertyHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/PropertyHandler.java b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/PropertyHandler.java new file mode 100644 index 0000000..396357e --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/extension/info/PropertyHandler.java @@ -0,0 +1,113 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.project.extension.info; + +import org.apache.cayenne.configuration.ConfigurationNode; +import org.apache.cayenne.configuration.xml.DataChannelMetaData; +import org.apache.cayenne.configuration.xml.DataMapHandler; +import org.apache.cayenne.configuration.xml.DbEntityHandler; +import org.apache.cayenne.configuration.xml.DbRelationshipHandler; +import org.apache.cayenne.configuration.xml.EmbeddableHandler; +import org.apache.cayenne.configuration.xml.NamespaceAwareNestedTagHandler; +import org.apache.cayenne.configuration.xml.ObjEntityHandler; +import org.apache.cayenne.configuration.xml.ObjRelationshipHandler; +import org.apache.cayenne.configuration.xml.ProcedureHandler; +import org.apache.cayenne.configuration.xml.QueryDescriptorHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +class PropertyHandler extends NamespaceAwareNestedTagHandler { + + static final String PROPERTY_TAG = "property"; + + private static final Logger logger = LoggerFactory.getLogger(PropertyHandler.class); + + private DataChannelMetaData metaData; + + PropertyHandler(NamespaceAwareNestedTagHandler parentHandler, DataChannelMetaData metaData) { + super(parentHandler); + setTargetNamespace(InfoExtension.NAMESPACE); + this.metaData = metaData; + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + switch (localName) { + case PROPERTY_TAG: + ConfigurationNode parentObject = getParentObject(); + String name = attributes.getValue("name"); + if(parentObject != null) { + ObjectInfo info = metaData.get(parentObject, ObjectInfo.class); + if(info == null) { + info = new ObjectInfo(); + metaData.add(parentObject, info); + } + String oldValue = info.put(name, attributes.getValue("value")); + if(oldValue != null) { + logger.warn("Duplicated property {} for object {}", name, parentObject); + } + } + return true; + } + + return false; + } + + @Override + protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String qName, Attributes attributes) { + return super.createChildTagHandler(namespaceURI, localName, qName, attributes); + } + + private ConfigurationNode getParentObject() { + if(parentHandler instanceof DataMapHandler) { + return ((DataMapHandler) parentHandler).getDataMap(); + } else if(parentHandler instanceof DbEntityHandler) { + return ((DbEntityHandler) parentHandler).getEntity(); + } else if(parentHandler instanceof ObjEntityHandler) { + return ((ObjEntityHandler) parentHandler).getEntity(); + } else if(parentHandler instanceof EmbeddableHandler) { + return ((EmbeddableHandler) parentHandler).getEmbeddable(); + } else if(parentHandler instanceof QueryDescriptorHandler) { + return ((QueryDescriptorHandler) parentHandler).getQueryDescriptor(); + } else if(parentHandler instanceof ProcedureHandler) { + return ((ProcedureHandler) parentHandler).getProcedure(); + } else if(parentHandler instanceof DbRelationshipHandler) { + return ((DbRelationshipHandler) parentHandler).getDbRelationship(); + } else if(parentHandler instanceof ObjRelationshipHandler) { + return ((ObjRelationshipHandler) parentHandler).getObjRelationship(); + } + + if(parentHandler instanceof NamespaceAwareNestedTagHandler) { + ContentHandler parentParentHandler = ((NamespaceAwareNestedTagHandler) parentHandler).getParentHandler(); + if(parentParentHandler instanceof DbEntityHandler) { + return ((DbEntityHandler) parentParentHandler).getLastAttribute(); + } else if(parentParentHandler instanceof ObjEntityHandler) { + return ((ObjEntityHandler) parentParentHandler).getLastAttribute(); + } + } + return null; + } +}
