http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbEntityHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbEntityHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbEntityHandler.java new file mode 100644 index 0000000..8de6bb1 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbEntityHandler.java @@ -0,0 +1,146 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.dba.TypesMapping; +import org.apache.cayenne.exp.ExpressionFactory; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class DbEntityHandler extends NamespaceAwareNestedTagHandler { + + private static final String DB_ENTITY_TAG = "db-entity"; + private static final String DB_ATTRIBUTE_TAG = "db-attribute"; + private static final String DB_KEY_GENERATOR_TAG = "db-key-generator"; + private static final String QUALIFIER_TAG = "qualifier"; + + private DataMap dataMap; + private DbEntity entity; + private DbAttribute lastAttribute; + + public DbEntityHandler(NamespaceAwareNestedTagHandler parentHandler, DataMap dataMap) { + super(parentHandler); + this.dataMap = dataMap; + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + switch (localName) { + case DB_ENTITY_TAG: + createDbEntity(attributes); + return true; + + case DB_ATTRIBUTE_TAG: + createDbAttribute(attributes); + return true; + + case QUALIFIER_TAG: + return true; + } + + return false; + } + + @Override + protected void processCharData(String localName, String data) { + switch (localName) { + case QUALIFIER_TAG: + createQualifier(data); + break; + } + } + + @Override + protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String qName, Attributes attributes) { + switch (localName) { + case DB_KEY_GENERATOR_TAG: + return new DbKeyGeneratorHandler(this, entity); + } + return super.createChildTagHandler(namespaceURI, localName, qName, attributes); + } + + private void createDbEntity(Attributes attributes) { + String name = attributes.getValue("name"); + entity = new DbEntity(name); + entity.setSchema(attributes.getValue("schema")); + entity.setCatalog(attributes.getValue("catalog")); + dataMap.addDbEntity(entity); + } + + private void createDbAttribute(Attributes attributes) { + String name = attributes.getValue("name"); + String type = attributes.getValue("type"); + + lastAttribute = new DbAttribute(name); + lastAttribute.setType(TypesMapping.getSqlTypeByName(type)); + entity.addAttribute(lastAttribute); + + String length = attributes.getValue("length"); + if (length != null) { + lastAttribute.setMaxLength(Integer.parseInt(length)); + } + + String precision = attributes.getValue("attributePrecision"); + if (precision != null) { + lastAttribute.setAttributePrecision(Integer.parseInt(precision)); + } + + // this is an obsolete 1.2 'precision' attribute that really meant 'scale' + String pseudoPrecision = attributes.getValue("precision"); + if (pseudoPrecision != null) { + lastAttribute.setScale(Integer.parseInt(pseudoPrecision)); + } + + String scale = attributes.getValue("scale"); + if (scale != null) { + lastAttribute.setScale(Integer.parseInt(scale)); + } + + lastAttribute.setPrimaryKey(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("isPrimaryKey"))); + lastAttribute.setMandatory(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("isMandatory"))); + lastAttribute.setGenerated(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("isGenerated"))); + } + + private void createQualifier(String qualifier) { + if (qualifier.trim().length() == 0) { + return; + } + + // qualifier can belong to ObjEntity, DbEntity or a query + if (entity != null) { + entity.setQualifier(ExpressionFactory.exp(qualifier)); + } + } + + public DbEntity getEntity() { + return entity; + } + + public DbAttribute getLastAttribute() { + return lastAttribute; + } +}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbKeyGeneratorHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbKeyGeneratorHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbKeyGeneratorHandler.java new file mode 100644 index 0000000..e76c4c3 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbKeyGeneratorHandler.java @@ -0,0 +1,117 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbKeyGenerator; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class DbKeyGeneratorHandler extends NamespaceAwareNestedTagHandler { + + private static final String DB_KEY_GENERATOR_TAG = "db-key-generator"; + private static final String DB_GENERATOR_TYPE_TAG = "db-generator-type"; + private static final String DB_GENERATOR_NAME_TAG = "db-generator-name"; + private static final String DB_KEY_CACHE_SIZE_TAG = "db-key-cache-size"; + + DbEntity entity; + + public DbKeyGeneratorHandler(NamespaceAwareNestedTagHandler parentHandler, DbEntity entity) { + super(parentHandler); + this.entity = entity; + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + switch (localName) { + case DB_KEY_GENERATOR_TAG: + createDbKeyGenerator(); + return true; + + case DB_GENERATOR_NAME_TAG: + case DB_GENERATOR_TYPE_TAG: + case DB_KEY_CACHE_SIZE_TAG: + return true; + } + + return false; + } + + @Override + protected void processCharData(String localName, String data) { + switch (localName) { + case DB_GENERATOR_TYPE_TAG: + setDbGeneratorType(data); + break; + + case DB_GENERATOR_NAME_TAG: + setDbGeneratorName(data); + break; + + case DB_KEY_CACHE_SIZE_TAG: + setDbKeyCacheSize(data); + break; + } + } + + private void createDbKeyGenerator() { + entity.setPrimaryKeyGenerator(new DbKeyGenerator()); + } + + private void setDbGeneratorType(String type) { + if (entity == null) { + return; + } + DbKeyGenerator pkGenerator = entity.getPrimaryKeyGenerator(); + pkGenerator.setGeneratorType(type); + if (pkGenerator.getGeneratorType() == null) { + entity.setPrimaryKeyGenerator(null); + } + } + + private void setDbGeneratorName(String name) { + if (entity == null) { + return; + } + DbKeyGenerator pkGenerator = entity.getPrimaryKeyGenerator(); + if (pkGenerator == null) { + return; + } + pkGenerator.setGeneratorName(name); + } + + private void setDbKeyCacheSize(String size) { + if (entity == null) { + return; + } + DbKeyGenerator pkGenerator = entity.getPrimaryKeyGenerator(); + if (pkGenerator == null) { + return; + } + try { + pkGenerator.setKeyCacheSize(new Integer(size.trim())); + } catch (Exception ex) { + pkGenerator.setKeyCacheSize(null); + } + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbRelationshipHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbRelationshipHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbRelationshipHandler.java new file mode 100644 index 0000000..b4730e5 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbRelationshipHandler.java @@ -0,0 +1,97 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbJoin; +import org.apache.cayenne.map.DbRelationship; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class DbRelationshipHandler extends NamespaceAwareNestedTagHandler { + + private static final String DB_RELATIONSHIP_TAG = "db-relationship"; + public static final String DB_ATTRIBUTE_PAIR_TAG = "db-attribute-pair"; + + private DataMap map; + + private DbRelationship dbRelationship; + + public DbRelationshipHandler(NamespaceAwareNestedTagHandler parentHandler, DataMap map) { + super(parentHandler); + this.map = map; + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + + switch (localName) { + case DB_RELATIONSHIP_TAG: + createRelationship(attributes); + return true; + + case DB_ATTRIBUTE_PAIR_TAG: + createDbAttributePair(attributes); + return true; + } + + return false; + } + + private void createRelationship(Attributes attributes) throws SAXException { + String name = attributes.getValue("name"); + if (name == null) { + throw new SAXException("DbRelationshipHandler::createRelationship() - missing \"name\" attribute."); + } + + String sourceName = attributes.getValue("source"); + if (sourceName == null) { + throw new SAXException("DbRelationshipHandler::createRelationship() - null source entity"); + } + + DbEntity source = map.getDbEntity(sourceName); + if (source == null) { + return; + } + + dbRelationship = new DbRelationship(name); + dbRelationship.setSourceEntity(source); + dbRelationship.setTargetEntityName(attributes.getValue("target")); + dbRelationship.setToMany(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("toMany"))); + dbRelationship.setToDependentPK(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("toDependentPK"))); + + source.addRelationship(dbRelationship); + } + + private void createDbAttributePair(Attributes attributes) { + DbJoin join = new DbJoin(dbRelationship); + join.setSourceName(attributes.getValue("source")); + join.setTargetName(attributes.getValue("target")); + dbRelationship.addJoin(join); + } + + public DbRelationship getDbRelationship() { + return dbRelationship; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DefaultDataChannelMetaData.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DefaultDataChannelMetaData.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DefaultDataChannelMetaData.java new file mode 100644 index 0000000..869abed --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DefaultDataChannelMetaData.java @@ -0,0 +1,91 @@ +/***************************************************************** + * 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.configuration.xml; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.cayenne.configuration.ConfigurationNode; + +/** + * <p> + * Default implementation of {@link DataChannelMetaData} that stores data in Map. + * </p> + * <p> + * This implementation is thread safe. + * </p> + * + * @see NoopDataChannelMetaData + * @since 4.1 + */ +public class DefaultDataChannelMetaData implements DataChannelMetaData { + + private Map<ConfigurationNode, Map<Class<?>, Object>> map; + + public DefaultDataChannelMetaData() { + map = new ConcurrentHashMap<>(); + } + + /** + * value.getClass() will be used under the hood to associate data with the key object. + * + * @param key object for which we want to store data + * @param value data to store + */ + @Override + public void add(ConfigurationNode key, Object value) { + if(key == null || value == null) { + return; + } + + Map<Class<?>, Object> data = map.get(key); + if(data == null) { + data = new ConcurrentHashMap<>(); + Map<Class<?>, Object> old = map.put(key, data); + // extra check in case if someone was fast enough + if(old != null) { + data.putAll(old); + } + } + data.put(value.getClass(), value); + } + + /** + * If either key or value is {@code null} then {@code null} will be returned. + * + * @param key object for wich we want meta data + * @param type meta data type class + * @param <T> data type + * @return value or {@code null} + */ + @Override + public <T> T get(ConfigurationNode key, Class<T> type) { + if(key == null || type == null) { + return null; + } + + Map<Class<?>, Object> data = map.get(key); + if(data == null) { + return null; + } + + return type.cast(data.get(type)); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DefaultHandlerFactory.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DefaultHandlerFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DefaultHandlerFactory.java new file mode 100644 index 0000000..5fd2293 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DefaultHandlerFactory.java @@ -0,0 +1,44 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.Attributes; + +/** + * @since 4.1 + */ +public class DefaultHandlerFactory implements HandlerFactory { + + private static Logger logger = LoggerFactory.getLogger(XMLDataChannelDescriptorLoader.class); + + @Override + public NamespaceAwareNestedTagHandler createHandler(String namespace, String localName, NamespaceAwareNestedTagHandler parent) { + return new NamespaceAwareNestedTagHandler(parent, namespace) { + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) { + logger.debug("Skipping unknown tag <{}:{}>", namespaceURI, localName); + return true; + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/EmbeddableAttributeHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/EmbeddableAttributeHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/EmbeddableAttributeHandler.java new file mode 100644 index 0000000..d0d4ae9 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/EmbeddableAttributeHandler.java @@ -0,0 +1,69 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.map.EmbeddedAttribute; +import org.apache.cayenne.map.ObjEntity; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class EmbeddableAttributeHandler extends NamespaceAwareNestedTagHandler { + + private static final String EMBEDDED_ATTRIBUTE_TAG = "embedded-attribute"; + private static final String EMBEDDABLE_ATTRIBUTE_OVERRIDE_TAG = "embeddable-attribute-override"; + + private ObjEntity entity; + + private EmbeddedAttribute embeddedAttribute; + + public EmbeddableAttributeHandler(NamespaceAwareNestedTagHandler parentHandler, ObjEntity entity) { + super(parentHandler); + this.entity = entity; + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + switch (localName) { + case EMBEDDED_ATTRIBUTE_TAG: + createEmbeddableAttribute(attributes); + return true; + + case EMBEDDABLE_ATTRIBUTE_OVERRIDE_TAG: + createEmbeddableAttributeOverride(attributes); + return true; + } + + return false; + } + + private void createEmbeddableAttribute(Attributes attributes) { + embeddedAttribute = new EmbeddedAttribute(attributes.getValue("name")); + embeddedAttribute.setType(attributes.getValue("type")); + entity.addAttribute(embeddedAttribute); + } + + private void createEmbeddableAttributeOverride(Attributes attributes) { + embeddedAttribute.addAttributeOverride(attributes.getValue("name"), + attributes.getValue("db-attribute-path")); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/EmbeddableHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/EmbeddableHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/EmbeddableHandler.java new file mode 100644 index 0000000..648474e --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/EmbeddableHandler.java @@ -0,0 +1,75 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.Embeddable; +import org.apache.cayenne.map.EmbeddableAttribute; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class EmbeddableHandler extends NamespaceAwareNestedTagHandler { + + private static final String EMBEDDABLE_TAG = "embeddable"; + private static final String EMBEDDABLE_ATTRIBUTE_TAG = "embeddable-attribute"; + + private DataMap map; + + private Embeddable embeddable; + + public EmbeddableHandler(NamespaceAwareNestedTagHandler parentHandler, DataMap map) { + super(parentHandler); + this.map = map; + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + switch (localName) { + case EMBEDDABLE_TAG: + createEmbeddable(attributes); + return true; + + case EMBEDDABLE_ATTRIBUTE_TAG: + createEmbeddableAttribute(attributes); + return true; + } + + return false; + } + + private void createEmbeddable(Attributes attributes) { + embeddable = new Embeddable(attributes.getValue("className")); + map.addEmbeddable(embeddable); + } + + private void createEmbeddableAttribute(Attributes attributes) { + EmbeddableAttribute ea = new EmbeddableAttribute(attributes.getValue("name")); + ea.setType(attributes.getValue("type")); + ea.setDbAttributeName(attributes.getValue("db-attribute-name")); + embeddable.addAttribute(ea); + } + + public Embeddable getEmbeddable() { + return embeddable; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/HandlerFactory.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/HandlerFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/HandlerFactory.java new file mode 100644 index 0000000..d02be06 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/HandlerFactory.java @@ -0,0 +1,30 @@ +/***************************************************************** + * 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.configuration.xml; + +/** + * Factory that creates handlers for unparsed elements. + * + * @since 4.1 + */ +public interface HandlerFactory { + + NamespaceAwareNestedTagHandler createHandler(String namespace, String localName, NamespaceAwareNestedTagHandler parent); +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/LoaderContext.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/LoaderContext.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/LoaderContext.java new file mode 100644 index 0000000..9507e4f --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/LoaderContext.java @@ -0,0 +1,63 @@ +/***************************************************************** + * 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.configuration.xml; + +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.cayenne.map.DataMap; +import org.xml.sax.XMLReader; + +/** + * @since 4.1 + */ +public class LoaderContext { + + Collection<DataMapLoaderListener> dataMapListeners; + + private XMLReader xmlReader; + + private HandlerFactory factory; + + public LoaderContext(XMLReader reader, HandlerFactory factory) { + this.xmlReader = reader; + this.factory = factory; + dataMapListeners = new ArrayList<>(); + } + + public HandlerFactory getFactory() { + return factory; + } + + public XMLReader getXmlReader() { + return xmlReader; + } + + public void addDataMapListener(DataMapLoaderListener dataMapLoaderListener) { + dataMapListeners.add(dataMapLoaderListener); + } + + public void dataMapLoaded(DataMap dataMap) { + for(DataMapLoaderListener listener : dataMapListeners) { + listener.onDataMapLoaded(dataMap); + } + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/NamespaceAwareNestedTagHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/NamespaceAwareNestedTagHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/NamespaceAwareNestedTagHandler.java new file mode 100644 index 0000000..ec332e5 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/NamespaceAwareNestedTagHandler.java @@ -0,0 +1,97 @@ +/***************************************************************** + * 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.configuration.xml; + +import java.util.Objects; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +/** + * Base class for handlers that can delegate execution of unknown tags to + * handlers produced by factory. + * + * @since 4.1 + */ +abstract public class NamespaceAwareNestedTagHandler extends SAXNestedTagHandler { + + protected String targetNamespace; + + private StringBuilder charactersBuffer = new StringBuilder(); + + public NamespaceAwareNestedTagHandler(LoaderContext loaderContext) { + super(loaderContext); + } + + public NamespaceAwareNestedTagHandler(SAXNestedTagHandler parentHandler, String targetNamespace) { + super(parentHandler); + this.targetNamespace = Objects.requireNonNull(targetNamespace); + } + + public NamespaceAwareNestedTagHandler(NamespaceAwareNestedTagHandler parentHandler) { + this(parentHandler, parentHandler.targetNamespace); + } + + abstract protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException; + + protected void processCharData(String localName, String data) { + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + charactersBuffer.append(ch, start, length); + } + + @Override + public final void startElement(String namespaceURI, String localName, + String qName, Attributes attributes) throws SAXException { + + ContentHandler childHandler = createChildTagHandler(namespaceURI, localName, qName, attributes); + + if(!namespaceURI.equals(targetNamespace) || !processElement(namespaceURI, localName, attributes)) { + // recursively pass element down into child handlers + childHandler.startElement(namespaceURI, localName, qName, attributes); + } + + // push child handler to the stack... + loaderContext.getXmlReader().setContentHandler(childHandler); + charactersBuffer.delete(0, charactersBuffer.length()); + } + + @Override + public void endElement(String namespaceURI, String localName, String qName) throws SAXException { + super.endElement(namespaceURI, localName, qName); + if(namespaceURI.equals(targetNamespace) && parentHandler instanceof NamespaceAwareNestedTagHandler) { + ((NamespaceAwareNestedTagHandler)parentHandler).processCharData(localName, charactersBuffer.toString()); + } + } + + @Override + protected ContentHandler createChildTagHandler(String namespaceURI, String localName, + String qName, Attributes attributes) { + // try to pass unknown tags to someone else + return loaderContext.getFactory().createHandler(namespaceURI, localName, this); + } + + public void setTargetNamespace(String targetNamespace) { + this.targetNamespace = targetNamespace; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/NoopDataChannelMetaData.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/NoopDataChannelMetaData.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/NoopDataChannelMetaData.java new file mode 100644 index 0000000..cbcb696 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/NoopDataChannelMetaData.java @@ -0,0 +1,42 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.configuration.ConfigurationNode; + +/** + * Noop implementation of {@link DataChannelMetaData}. + * Used by Cayenne runtime by default as it doesn't need this information. + * + * @see DefaultDataChannelMetaData + * @since 4.1 + */ +public class NoopDataChannelMetaData implements DataChannelMetaData { + + @Override + public void add(ConfigurationNode key, Object value) { + // noop + } + + @Override + public <T> T get(ConfigurationNode key, Class<T> type) { + return null; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjEntityHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjEntityHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjEntityHandler.java new file mode 100644 index 0000000..e9ee9aa --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjEntityHandler.java @@ -0,0 +1,210 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.exp.ExpressionFactory; +import org.apache.cayenne.map.CallbackDescriptor; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.ObjAttribute; +import org.apache.cayenne.map.ObjEntity; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class ObjEntityHandler extends NamespaceAwareNestedTagHandler { + + private static final String OBJ_ENTITY_TAG = "obj-entity"; + private static final String OBJ_ATTRIBUTE_TAG = "obj-attribute"; + private static final String OBJ_ATTRIBUTE_OVERRIDE_TAG = "attribute-override"; + private static final String EMBEDDED_ATTRIBUTE_TAG = "embedded-attribute"; + private static final String QUALIFIER_TAG = "qualifier"; + + // lifecycle listeners and callbacks related + private static final String POST_ADD_TAG = "post-add"; + private static final String PRE_PERSIST_TAG = "pre-persist"; + private static final String POST_PERSIST_TAG = "post-persist"; + private static final String PRE_UPDATE_TAG = "pre-update"; + private static final String POST_UPDATE_TAG = "post-update"; + private static final String PRE_REMOVE_TAG = "pre-remove"; + private static final String POST_REMOVE_TAG = "post-remove"; + private static final String POST_LOAD_TAG = "post-load"; + + private DataMap map; + + private ObjEntity entity; + + private ObjAttribute lastAttribute; + + public ObjEntityHandler(NamespaceAwareNestedTagHandler parentHandler, DataMap map) { + super(parentHandler); + this.map = map; + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + switch (localName) { + case OBJ_ENTITY_TAG: + createObjEntity(attributes); + return true; + + case OBJ_ATTRIBUTE_TAG: + createObjAttribute(attributes); + return true; + + case OBJ_ATTRIBUTE_OVERRIDE_TAG: + processStartAttributeOverride(attributes); + return true; + + case QUALIFIER_TAG: + return true; + + case POST_ADD_TAG: + case PRE_PERSIST_TAG: + case POST_PERSIST_TAG: + case PRE_UPDATE_TAG: + case POST_UPDATE_TAG: + case PRE_REMOVE_TAG: + case POST_REMOVE_TAG: + case POST_LOAD_TAG: + createCallback(localName, attributes); + return true; + } + + return false; + } + + @Override + protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String qName, Attributes attributes) { + if(namespaceURI.equals(targetNamespace)) { + switch (localName) { + case EMBEDDED_ATTRIBUTE_TAG: + return new EmbeddableAttributeHandler(this, entity); + } + } + + return super.createChildTagHandler(namespaceURI, localName, qName, attributes); + } + + @Override + protected void processCharData(String localName, String data) { + switch (localName) { + case QUALIFIER_TAG: + createQualifier(data); + break; + } + } + + private void createObjEntity(Attributes attributes) { + entity = new ObjEntity(attributes.getValue("name")); + entity.setClassName(attributes.getValue("className")); + entity.setClientClassName(attributes.getValue("clientClassName")); + entity.setAbstract(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("abstract"))); + entity.setReadOnly(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("readOnly"))); + entity.setServerOnly(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("serverOnly"))); + if ("optimistic".equals(attributes.getValue("", "lock-type"))) { + entity.setDeclaredLockType(ObjEntity.LOCK_TYPE_OPTIMISTIC); + } + + String superEntityName = attributes.getValue("superEntityName"); + if (superEntityName != null) { + entity.setSuperEntityName(superEntityName); + } else { + entity.setSuperClassName(attributes.getValue("superClassName")); + entity.setClientSuperClassName(attributes.getValue("clientSuperClassName")); + } + entity.setDbEntityName(attributes.getValue("dbEntityName")); + + map.addObjEntity(entity); + } + + private void createObjAttribute(Attributes attributes) { + String dbPath = attributes.getValue("db-attribute-path"); + if (dbPath == null) { + dbPath = attributes.getValue("db-attribute-name"); + } + + lastAttribute = new ObjAttribute(attributes.getValue("name")); + lastAttribute.setType(attributes.getValue("type")); + lastAttribute.setUsedForLocking(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("lock"))); + lastAttribute.setDbAttributePath(dbPath); + entity.addAttribute(lastAttribute); + } + + private void processStartAttributeOverride(Attributes attributes) { + entity.addAttributeOverride(attributes.getValue("name"), + attributes.getValue("db-attribute-path")); + } + + private CallbackDescriptor getCallbackDescriptor(String type) { + if (entity == null) { + return null; + } + + switch (type) { + case POST_ADD_TAG: + return entity.getCallbackMap().getPostAdd(); + case PRE_PERSIST_TAG: + return entity.getCallbackMap().getPrePersist(); + case POST_PERSIST_TAG: + return entity.getCallbackMap().getPostPersist(); + case PRE_UPDATE_TAG: + return entity.getCallbackMap().getPreUpdate(); + case POST_UPDATE_TAG: + return entity.getCallbackMap().getPostUpdate(); + case PRE_REMOVE_TAG: + return entity.getCallbackMap().getPreRemove(); + case POST_REMOVE_TAG: + return entity.getCallbackMap().getPostRemove(); + case POST_LOAD_TAG: + return entity.getCallbackMap().getPostLoad(); + } + + return null; + } + + private void createCallback(String type, Attributes attributes) { + String methodName = attributes.getValue("method-name"); + CallbackDescriptor descriptor = getCallbackDescriptor(type); + if(descriptor != null) { + descriptor.addCallbackMethod(methodName); + } + } + + private void createQualifier(String qualifier) { + if (qualifier.trim().length() == 0) { + return; + } + + if (entity != null) { + entity.setDeclaredQualifier(ExpressionFactory.exp(qualifier)); + } + } + + public ObjEntity getEntity() { + return entity; + } + + public ObjAttribute getLastAttribute() { + return lastAttribute; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjRelationshipHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjRelationshipHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjRelationshipHandler.java new file mode 100644 index 0000000..63be65d --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjRelationshipHandler.java @@ -0,0 +1,109 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.DeleteRule; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class ObjRelationshipHandler extends NamespaceAwareNestedTagHandler { + + public static final String OBJ_RELATIONSHIP_TAG = "obj-relationship"; + + @Deprecated + public static final String DB_RELATIONSHIP_REF_TAG = "db-relationship-ref"; + + private DataMap map; + + private ObjRelationship objRelationship; + + public ObjRelationshipHandler(NamespaceAwareNestedTagHandler parentHandler, DataMap map) { + super(parentHandler); + this.map = map; + } + + @SuppressWarnings("deprecation") + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + switch (localName) { + case OBJ_RELATIONSHIP_TAG: + addObjRelationship(attributes); + return true; + + case DB_RELATIONSHIP_REF_TAG: + addDbRelationshipRef(attributes); + return true; + } + + return false; + } + + /** + * <db-relationship-ref> tag deprecated + */ + @Deprecated + private void addDbRelationshipRef(Attributes attributes) throws SAXException { + String name = attributes.getValue("name"); + if (name == null) { + throw new SAXException("ObjRelationshipHandler::addDbRelationshipRef() - null DbRelationship name for " + + objRelationship.getName()); + } + + String path = objRelationship.getDbRelationshipPath(); + objRelationship.setDbRelationshipPath((path != null) ? path + "." + name : name); + } + + private void addObjRelationship(Attributes attributes) throws SAXException { + String name = attributes.getValue("name"); + if (null == name) { + throw new SAXException("ObjRelationshipHandler::addObjRelationship() - unable to parse target."); + } + + String sourceName = attributes.getValue("source"); + if (sourceName == null) { + throw new SAXException("ObjRelationshipHandler::addObjRelationship() - unable to parse source."); + } + + ObjEntity source = map.getObjEntity(sourceName); + if (source == null) { + throw new SAXException("ObjRelationshipHandler::addObjRelationship() - unable to find source " + sourceName); + } + + objRelationship = new ObjRelationship(name); + objRelationship.setSourceEntity(source); + objRelationship.setTargetEntityName(attributes.getValue("target")); + objRelationship.setDeleteRule(DeleteRule.deleteRuleForName(attributes.getValue("deleteRule"))); + objRelationship.setUsedForLocking(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("lock"))); + objRelationship.setDeferredDbRelationshipPath((attributes.getValue("db-relationship-path"))); + objRelationship.setCollectionType(attributes.getValue("collection-type")); + objRelationship.setMapKey(attributes.getValue("map-key")); + source.addRelationship(objRelationship); + } + + public ObjRelationship getObjRelationship() { + return objRelationship; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ProcedureHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ProcedureHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ProcedureHandler.java new file mode 100644 index 0000000..72e6a53 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ProcedureHandler.java @@ -0,0 +1,114 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.dba.TypesMapping; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.Procedure; +import org.apache.cayenne.map.ProcedureParameter; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class ProcedureHandler extends NamespaceAwareNestedTagHandler { + + private static final String PROCEDURE_TAG = "procedure"; + private static final String PROCEDURE_PARAMETER_TAG = "procedure-parameter"; + + private DataMap map; + + private Procedure procedure; + + public ProcedureHandler(NamespaceAwareNestedTagHandler parentHandler, DataMap map) { + super(parentHandler); + this.map = map; + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + switch (localName) { + case PROCEDURE_TAG: + addProcedure(attributes); + return true; + + case PROCEDURE_PARAMETER_TAG: + addProcedureParameter(attributes); + return true; + } + + return false; + } + + private void addProcedure(Attributes attributes) throws SAXException{ + String name = attributes.getValue("name"); + String returningValue = attributes.getValue("returningValue"); + if (null == name) { + throw new SAXException("ProcedureHandler::addProcedure() - no procedure name."); + } + + procedure = new Procedure(name); + procedure.setReturningValue(returningValue != null && returningValue.equalsIgnoreCase(DataMapHandler.TRUE)); + procedure.setSchema(attributes.getValue("schema")); + procedure.setCatalog(attributes.getValue("catalog")); + map.addProcedure(procedure); + } + + private void addProcedureParameter(Attributes attributes) throws SAXException { + + String name = attributes.getValue("name"); + if (name == null) { + throw new SAXException("ProcedureHandler::addProcedureParameter() - no procedure parameter name."); + } + + ProcedureParameter parameter = new ProcedureParameter(name); + + String type = attributes.getValue("type"); + if (type != null) { + parameter.setType(TypesMapping.getSqlTypeByName(type)); + } + + String length = attributes.getValue("length"); + if (length != null) { + parameter.setMaxLength(Integer.parseInt(length)); + } + + String precision = attributes.getValue("precision"); + if (precision != null) { + parameter.setPrecision(Integer.parseInt(precision)); + } + + String direction = attributes.getValue("direction"); + if ("in".equals(direction)) { + parameter.setDirection(ProcedureParameter.IN_PARAMETER); + } else if ("out".equals(direction)) { + parameter.setDirection(ProcedureParameter.OUT_PARAMETER); + } else if ("in_out".equals(direction)) { + parameter.setDirection(ProcedureParameter.IN_OUT_PARAMETER); + } + + procedure.addCallParameter(parameter); + } + + public Procedure getProcedure() { + return procedure; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/QueryDescriptorHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/QueryDescriptorHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/QueryDescriptorHandler.java new file mode 100644 index 0000000..4034184 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/QueryDescriptorHandler.java @@ -0,0 +1,191 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.QueryDescriptor; +import org.apache.cayenne.map.QueryDescriptorLoader; +import org.apache.cayenne.util.Util; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class QueryDescriptorHandler extends NamespaceAwareNestedTagHandler { + + private static final String QUERY_DESCRIPTOR_TAG = "query"; + private static final String QUERY_SQL_TAG = "sql"; + private static final String QUERY_EJBQL_TAG = "ejbql"; + private static final String QUERY_QUALIFIER_TAG = "qualifier"; + private static final String QUERY_ORDERING_TAG = "ordering"; + private static final String QUERY_PREFETCH_TAG = "prefetch"; + + public static final String PROPERTY_TAG = "property"; + + private DataMap map; + + private QueryDescriptorLoader queryBuilder; + private QueryDescriptor descriptor; + private boolean changed; + + private String sqlKey; + private String descending; + private String ignoreCase; + + public QueryDescriptorHandler(NamespaceAwareNestedTagHandler parentHandler, DataMap map) { + super(parentHandler); + this.map = map; + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + + switch (localName) { + case QUERY_DESCRIPTOR_TAG: + addQueryDescriptor(attributes); + return true; + + case PROPERTY_TAG: + addQueryDescriptorProperty(attributes); + return true; + + case QUERY_SQL_TAG: + this.sqlKey = attributes.getValue("adapter-class"); + return true; + + case QUERY_ORDERING_TAG: + createQueryOrdering(attributes); + return true; + + case QUERY_EJBQL_TAG: + case QUERY_QUALIFIER_TAG: + case QUERY_PREFETCH_TAG: + return true; + } + + return false; + } + + @Override + protected void processCharData(String localName, String data) { + switch (localName) { + case QUERY_SQL_TAG: + queryBuilder.addSql(data, sqlKey); + break; + + case QUERY_EJBQL_TAG: + queryBuilder.setEjbql(data); + break; + + case QUERY_QUALIFIER_TAG: + createQualifier(data); + break; + + case QUERY_ORDERING_TAG: + addQueryOrdering(data); + break; + + case QUERY_PREFETCH_TAG: + queryBuilder.addPrefetch(data); + break; + } + } + + @Override + protected void beforeScopeEnd() { + map.addQueryDescriptor(getQueryDescriptor()); + } + + private void addQueryDescriptor(Attributes attributes) throws SAXException { + String name = attributes.getValue("name"); + if (null == name) { + throw new SAXException("QueryDescriptorHandler::addQueryDescriptor() - no query name."); + } + + queryBuilder = new QueryDescriptorLoader(); + queryBuilder.setName(name); + + String type = attributes.getValue("type"); + // Legacy format support (v7 and older) + if(type == null) { + queryBuilder.setLegacyFactory(attributes.getValue("factory")); + } else { + queryBuilder.setQueryType(type); + } + + String rootName = attributes.getValue("root-name"); + queryBuilder.setRoot(map, attributes.getValue("root"), rootName); + + // TODO: Andrus, 2/13/2006 'result-type' is only used in ProcedureQuery + // and is deprecated in 1.2 + String resultEntity = attributes.getValue("result-entity"); + if (!Util.isEmptyString(resultEntity)) { + queryBuilder.setResultEntity(resultEntity); + } + + changed = true; + } + + private void addQueryDescriptorProperty(Attributes attributes) throws SAXException { + String name = attributes.getValue("name"); + if (null == name) { + throw new SAXException("QueryDescriptorHandler::addQueryDescriptorProperty() - no property name."); + } + + String value = attributes.getValue("value"); + if (null == value) { + throw new SAXException("QueryDescriptorHandler::addQueryDescriptorProperty() - no property value."); + } + + queryBuilder.addProperty(name, value); + changed = true; + } + + private void createQualifier(String qualifier) { + if (qualifier.trim().length() == 0) { + return; + } + + queryBuilder.setQualifier(qualifier); + changed = true; + } + + private void createQueryOrdering(Attributes attributes) { + descending = attributes.getValue("descending"); + ignoreCase = attributes.getValue("ignore-case"); + } + + private void addQueryOrdering(String path) { + queryBuilder.addOrdering(path, descending, ignoreCase); + changed = true; + } + + public QueryDescriptor getQueryDescriptor() { + if(queryBuilder == null) { + return null; + } + if(descriptor == null || changed) { + descriptor = queryBuilder.buildQueryDescriptor(); + changed = false; + } + return descriptor; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/RootDataMapHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/RootDataMapHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/RootDataMapHandler.java new file mode 100644 index 0000000..dba5022 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/RootDataMapHandler.java @@ -0,0 +1,51 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.map.DataMap; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +/** + * @since 4.1 + */ +public class RootDataMapHandler extends NamespaceAwareNestedTagHandler { + + public RootDataMapHandler(LoaderContext loaderContext) { + super(loaderContext); + setTargetNamespace(DataMap.SCHEMA_XSD); + } + + @Override + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + return false; + } + + @Override + protected ContentHandler createChildTagHandler(String namespaceURI, String localName, String qName, Attributes attributes) { + if(targetNamespace.equals(namespaceURI) && "data-map".equals(localName)) { + return new DataMapHandler(this); + } + + return super.createChildTagHandler(namespaceURI, localName, qName, attributes); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/SAXNestedTagHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/SAXNestedTagHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/SAXNestedTagHandler.java new file mode 100644 index 0000000..d2d4e04 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/SAXNestedTagHandler.java @@ -0,0 +1,175 @@ +/***************************************************************** + * 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.configuration.xml; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * A superclass of nested tag handlers for parsing of XML documents with SAX. + * This class is not namespace aware, i.e. tags like <info:property/> and <property/> + * will be treated as equal. + * Use {@link NamespaceAwareNestedTagHandler} if you need to process namespaces. + * + * @see NamespaceAwareNestedTagHandler + * @since 3.1 + * @since 4.1 redesigned and moved from {@link org.apache.cayenne.configuration} package + */ +public class SAXNestedTagHandler extends DefaultHandler { + + private final static Locator NOOP_LOCATOR = new Locator() { + + public int getColumnNumber() { + return -1; + } + + public int getLineNumber() { + return -1; + } + + public String getPublicId() { + return "<unknown>"; + } + + public String getSystemId() { + return "<unknown>"; + } + }; + + protected LoaderContext loaderContext; + protected ContentHandler parentHandler; + protected Locator locator; + + public SAXNestedTagHandler(LoaderContext loaderContext) { + this.loaderContext = Objects.requireNonNull(loaderContext); + this.locator = NOOP_LOCATOR; + } + + public SAXNestedTagHandler(SAXNestedTagHandler parentHandler) { + this.parentHandler = Objects.requireNonNull(parentHandler); + this.loaderContext = Objects.requireNonNull(parentHandler.loaderContext); + + locator = parentHandler.locator; + if (locator == null) { + locator = NOOP_LOCATOR; + } + } + + protected String unexpectedTagMessage(String tagFound, String... tagsExpected) { + + List<String> expected = tagsExpected != null + ? Arrays.asList(tagsExpected) + : Collections.<String> emptyList(); + + return String.format("tag <%s> is unexpected at [%d,%d]. The following tags are allowed here: %s", + tagFound, + locator.getColumnNumber(), + locator.getLineNumber(), + expected); + } + + /** + * Main method to process XML content. + * Should be override in subclasses, by default do nothing. + * Return value should be true if tag was fully processed and shouldn't be passed down to child handler. + * + * @param namespaceURI namespace for tag + * @param localName tag local name (i.e. w/o namespace prefix) + * @param attributes tag attributes + * + * @return true if tag was processed + * + * @throws SAXException can be thrown to abort parsing + * + * @see #createChildTagHandler(String, String, String, Attributes) + */ + protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException { + return true; + } + + /** + * Callback method that is called before this handler pushed out of parsers stack. + * Can be used to flush some aggregate state. + */ + protected void beforeScopeEnd() { + } + + /** + * This method should be used to create nested handlers to process children elements. + * This method should never return {@code null}. + * + * @param namespaceURI namespace for tag + * @param localName tag local name (i.e. w/o namespace prefix) + * @param qName tag full name (i.e. with namespace prefix) + * @param attributes tag attributes + * @return new handler to process child tag + */ + protected ContentHandler createChildTagHandler(String namespaceURI, String localName, + String qName, Attributes attributes) { + // loose handling of unrecognized tags - just ignore them + return new SAXNestedTagHandler(this); + } + + protected void stop() { + beforeScopeEnd(); + // pop self from the handler stack + loaderContext.getXmlReader().setContentHandler(parentHandler); + } + + /** + * This method directly called by SAX parser, do not override it directly, + * use {@link #processElement(String, String, Attributes)} method instead to process content. + * + * @see #createChildTagHandler(String, String, String, Attributes) + */ + @Override + public void startElement(String namespaceURI, String localName, + String qName, Attributes attributes) throws SAXException { + ContentHandler childHandler = createChildTagHandler(namespaceURI, localName, qName, attributes); + + if(!processElement(namespaceURI, localName, attributes)) { + childHandler.startElement(namespaceURI, localName, qName, attributes); + } + + // push child handler to the stack... + loaderContext.getXmlReader().setContentHandler(childHandler); + } + + @Override + public void endElement(String namespaceURI, String localName, String qName) throws SAXException { + stop(); + } + + @Override + public void setDocumentLocator(Locator locator) { + this.locator = locator; + } + + public ContentHandler getParentHandler() { + return parentHandler; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/XMLDataChannelDescriptorLoader.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/XMLDataChannelDescriptorLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/XMLDataChannelDescriptorLoader.java new file mode 100644 index 0000000..e9d104e --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/XMLDataChannelDescriptorLoader.java @@ -0,0 +1,149 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.ConfigurationException; +import org.apache.cayenne.configuration.ConfigurationNameMapper; +import org.apache.cayenne.configuration.ConfigurationTree; +import org.apache.cayenne.configuration.DataChannelDescriptor; +import org.apache.cayenne.configuration.DataChannelDescriptorLoader; +import org.apache.cayenne.configuration.DataMapLoader; +import org.apache.cayenne.di.AdhocObjectFactory; +import org.apache.cayenne.di.Inject; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.resource.Resource; +import org.apache.cayenne.util.Util; +import org.slf4j.LoggerFactory; +import org.slf4j.Logger; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; + +/** + * @since 3.1 + * @since 4.1 moved from org.apache.cayenne.configuration package + */ +public class XMLDataChannelDescriptorLoader implements DataChannelDescriptorLoader { + + private static Logger logger = LoggerFactory.getLogger(XMLDataChannelDescriptorLoader.class); + + static final String CURRENT_PROJECT_VERSION = "10"; + + /** + * @deprecated the caller should use password resolving strategy instead of + * resolving the password on the spot. For one thing this can be + * used in the Modeler and no password may be available. + */ + @Deprecated + static String passwordFromURL(URL url) { + InputStream inputStream; + String password = null; + + try { + inputStream = url.openStream(); + password = passwordFromInputStream(inputStream); + } catch (IOException exception) { + // Log the error while trying to open the stream. A null + // password will be returned as a result. + logger.warn(exception.getMessage(), exception); + } + + return password; + } + + /** + * @deprecated the caller should use password resolving strategy instead of + * resolving the password on the spot. For one thing this can be + * used in the Modeler and no password may be available. + */ + @Deprecated + static String passwordFromInputStream(InputStream inputStream) { + String password = null; + + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));) { + + password = bufferedReader.readLine(); + } catch (IOException exception) { + logger.warn(exception.getMessage(), exception); + } finally { + + try { + inputStream.close(); + } catch (IOException ignored) { + } + } + + return password; + } + + @Inject + protected DataMapLoader dataMapLoader; + + @Inject + protected ConfigurationNameMapper nameMapper; + + @Inject + protected AdhocObjectFactory objectFactory; + + @Inject + protected HandlerFactory handlerFactory; + + @Override + public ConfigurationTree<DataChannelDescriptor> load(Resource configurationResource) throws ConfigurationException { + + if (configurationResource == null) { + throw new NullPointerException("Null configurationResource"); + } + + URL configurationURL = configurationResource.getURL(); + + logger.info("Loading XML configuration resource from " + configurationURL); + + final DataChannelDescriptor descriptor = new DataChannelDescriptor(); + descriptor.setConfigurationSource(configurationResource); + descriptor.setName(nameMapper.configurationNodeName(DataChannelDescriptor.class, configurationResource)); + + try(InputStream in = configurationURL.openStream()) { + XMLReader parser = Util.createXmlReader(); + LoaderContext loaderContext = new LoaderContext(parser, handlerFactory); + loaderContext.addDataMapListener(new DataMapLoaderListener() { + @Override + public void onDataMapLoaded(DataMap dataMap) { + descriptor.getDataMaps().add(dataMap); + } + }); + + DataChannelHandler rootHandler = new DataChannelHandler(this, descriptor, loaderContext); + parser.setContentHandler(rootHandler); + parser.setErrorHandler(rootHandler); + parser.parse(new InputSource(in)); + } catch (Exception e) { + throw new ConfigurationException("Error loading configuration from %s", e, configurationURL); + } + + // TODO: andrus 03/10/2010 - actually provide load failures here... + return new ConfigurationTree<>(descriptor, null); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/XMLDataMapLoader.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/XMLDataMapLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/XMLDataMapLoader.java new file mode 100644 index 0000000..eb82d32 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/XMLDataMapLoader.java @@ -0,0 +1,102 @@ +/***************************************************************** + * 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.configuration.xml; + +import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.configuration.DataMapLoader; +import org.apache.cayenne.di.Inject; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.resource.Resource; +import org.apache.cayenne.util.Util; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; + +import java.io.InputStream; + +/** + * @since 3.1 + * @since 4.1 moved from org.apache.cayenne.configuration package + */ +public class XMLDataMapLoader implements DataMapLoader { + + private static final String DATA_MAP_LOCATION_SUFFIX = ".map.xml"; + + @Inject + protected HandlerFactory handlerFactory; + + private DataMap map; + + public synchronized DataMap load(Resource configurationResource) throws CayenneRuntimeException { + try(InputStream in = configurationResource.getURL().openStream()) { + XMLReader parser = Util.createXmlReader(); + LoaderContext loaderContext = new LoaderContext(parser, handlerFactory); + loaderContext.addDataMapListener(new DataMapLoaderListener() { + @Override + public void onDataMapLoaded(DataMap dataMap) { + map = dataMap; + } + }); + RootDataMapHandler rootHandler = new RootDataMapHandler(loaderContext); + + parser.setContentHandler(rootHandler); + parser.setErrorHandler(rootHandler); + parser.parse(new InputSource(in)); + } catch (Exception e) { + throw new CayenneRuntimeException("Error loading configuration from %s", e, configurationResource.getURL()); + } + + if(map == null) { + throw new CayenneRuntimeException("Unable to load data map from %s", configurationResource.getURL()); + } + + if(map.getName() == null) { + // set name based on location if no name provided by map itself + map.setName(mapNameFromLocation(configurationResource.getURL().getFile())); + } + return map; + } + + /** + * Helper method to guess the map name from its location. + */ + protected String mapNameFromLocation(String location) { + if (location == null) { + return "Untitled"; + } + + int lastSlash = location.lastIndexOf('/'); + if (lastSlash < 0) { + lastSlash = location.lastIndexOf('\\'); + } + + if (lastSlash >= 0 && lastSlash + 1 < location.length()) { + location = location.substring(lastSlash + 1); + } + + if (location.endsWith(DATA_MAP_LOCATION_SUFFIX)) { + location = location.substring(0, location.length() - DATA_MAP_LOCATION_SUFFIX.length()); + } + + return location; + } + + public void setHandlerFactory(HandlerFactory handlerFactory) { + this.handlerFactory = handlerFactory; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/conn/DataSourceInfo.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/DataSourceInfo.java b/cayenne-server/src/main/java/org/apache/cayenne/conn/DataSourceInfo.java index f51c8f0..0647fbc 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/conn/DataSourceInfo.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/conn/DataSourceInfo.java @@ -21,6 +21,7 @@ package org.apache.cayenne.conn; import java.io.Serializable; +import org.apache.cayenne.configuration.ConfigurationNodeVisitor; import org.apache.cayenne.configuration.PasswordEncoding; import org.apache.cayenne.configuration.PlainTextPasswordEncoder; import org.apache.cayenne.di.DIRuntimeException; @@ -134,58 +135,46 @@ public class DataSourceInfo implements Cloneable, Serializable, XMLSerializable /** * @since 3.1 */ - public void encodeAsXML(XMLEncoder encoder) { - encoder.println("<data-source>"); - encoder.indent(1); - - encoder.print("<driver"); - encoder.printAttribute("value", jdbcDriver); - encoder.println("/>"); + @Override + public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) { + encoder.start("data-source"); - encoder.print("<url"); - encoder.printAttribute("value", dataSourceUrl); - encoder.println("/>"); + encoder.start("driver").attribute("value", jdbcDriver).end(); + encoder.start("url").attribute("value", dataSourceUrl).end(); - encoder.print("<connectionPool"); - encoder.printAttribute("min", String.valueOf(minConnections)); - encoder.printAttribute("max", String.valueOf(maxConnections)); - encoder.println("/>"); + encoder.start("connectionPool") + .attribute("min", minConnections) + .attribute("max", String.valueOf(maxConnections)) + .end(); - encoder.print("<login"); - encoder.printAttribute("userName", userName); + encoder.start("login").attribute("userName", userName); if (DataSourceInfo.PASSWORD_LOCATION_MODEL.equals(passwordLocation)) { - PasswordEncoding passwordEncoder = getPasswordEncoder(); - if (passwordEncoder != null) { String passwordEncoded = passwordEncoder.encodePassword(password, passwordEncoderKey); - encoder.printAttribute("password", passwordEncoded); + encoder.attribute("password", passwordEncoded); } } if (!PlainTextPasswordEncoder.class.getName().equals(passwordEncoderClass)) { - encoder.printAttribute("encoderClass", passwordEncoderClass); + encoder.attribute("encoderClass", passwordEncoderClass); } - encoder.printAttribute("encoderKey", passwordEncoderKey); + encoder.attribute("encoderKey", passwordEncoderKey); if (!DataSourceInfo.PASSWORD_LOCATION_MODEL.equals(passwordLocation)) { - encoder.printAttribute("passwordLocation", passwordLocation); + encoder.attribute("passwordLocation", passwordLocation); } // TODO: this is very not nice... we need to clean up the whole - // DataSourceInfo - // to avoid returning arbitrary labels... + // DataSourceInfo to avoid returning arbitrary labels... String passwordSource = getPasswordSource(); if (!"Not Applicable".equals(passwordSource)) { - encoder.printAttribute("passwordSource", passwordSource); + encoder.attribute("passwordSource", passwordSource); } - encoder.println("/>"); - - encoder.indent(-1); - encoder.println("</data-source>"); + encoder.end().end(); } public DataSourceInfo cloneInfo() { http://git-wip-us.apache.org/repos/asf/cayenne/blob/c58b6f40/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java index 0d35cea..77a8cdf 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.configuration.ConfigurationNodeVisitor; import org.apache.cayenne.exp.parser.ASTScalar; import org.apache.cayenne.util.ConversionUtil; import org.apache.cayenne.util.HashCodeBuilder; @@ -679,14 +680,15 @@ public abstract class Expression implements Serializable, XMLSerializable { * * @since 1.1 */ - public void encodeAsXML(XMLEncoder encoder) { - encoder.print("<![CDATA["); + @Override + public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) { + StringBuilder sb = new StringBuilder(); try { - appendAsString(encoder.getPrintWriter()); + appendAsString(sb); } catch (IOException e) { throw new CayenneRuntimeException("Unexpected IO exception appending to PrintWriter", e); } - encoder.print("]]>"); + encoder.cdata(sb.toString(), true); } /**
