All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jsefa.rbf.RbfIOFactory Maven / Gradle / Ivy

Go to download

JSefa (Java Simple exchange format api) is a simple library for stream-based serialization of java objects to XML, CSV, FLR or any other format and back again using an iterator-style interface independent of the serialization format. The mapping between java object types and types of the serialization format (e. g. xml complex element types) can be defined either by annotating the java classes or programmatically using a simple API. The current implementation supports XML, CSV and FLR - for XML it is based on JSR 173.

The newest version!
/*
 * Copyright 2007 the original author or authors.
 *
 * Licensed 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 net.sf.jsefa.rbf;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import net.sf.jsefa.IOFactory;
import net.sf.jsefa.IOFactoryException;
import net.sf.jsefa.common.config.Configuration;
import net.sf.jsefa.common.mapping.TypeMapping;
import net.sf.jsefa.common.validator.Validator;
import net.sf.jsefa.common.validator.traversal.TraversingValidatorFactory;
import net.sf.jsefa.rbf.mapping.RbfComplexTypeMapping;
import net.sf.jsefa.rbf.mapping.RbfEntryPoint;
import net.sf.jsefa.rbf.mapping.RbfListTypeMapping;
import net.sf.jsefa.rbf.mapping.RbfNodeType;
import net.sf.jsefa.rbf.mapping.RbfTypeMappingRegistry;
import net.sf.jsefa.rbf.mapping.RecordMapping;

/**
 * Abstract super class for RBF factories.
 * 

* Instances of this class are immutable and thread-safe. This must be true for all subclasses, too. * * @author Norman Lahme-Huetig * * @param the configuration type * @param the serializer type * @param the deserializer type */ public abstract class RbfIOFactory, S extends RbfSerializer, D extends RbfDeserializer> implements IOFactory { private final C config; private final RbfEntryPoint entryPoint; private final ConcurrentMap entryPointsByPrefix; private final ConcurrentMap, RbfEntryPoint> entryPointsByObjectType; private final boolean withPrefix; /** * Constructs a new RbfIOFactory. * * @param config the configuration */ @SuppressWarnings("unchecked") protected RbfIOFactory(C config) { if (config.getEntryPoints().size() == 0) { throw new IOFactoryException("No entry points given"); } this.withPrefix = prefixRequired(config.getEntryPoints()); this.config = (C) config.createCopy(); this.entryPointsByObjectType = new ConcurrentHashMap, RbfEntryPoint>(); TraversingValidatorFactory traversingValidatorFactory = new TraversingValidatorFactory( config.getTypeMappingRegistry(), config.getObjectAccessorProvider()); if (this.withPrefix) { this.entryPointsByPrefix = new ConcurrentHashMap(); for (RbfEntryPoint anEntryPoint : config.getEntryPoints()) { Validator validator = traversingValidatorFactory.create(anEntryPoint.getDataTypeName(), anEntryPoint .getValidator()); RbfEntryPoint validationEntryPoint = new RbfEntryPoint(anEntryPoint.getDataTypeName(), anEntryPoint .getDesignator(), validator); Class objectType = getObjectType(anEntryPoint.getDataTypeName()); assertPrefixDeclared(validationEntryPoint, objectType); this.entryPointsByObjectType.put(objectType, validationEntryPoint); this.entryPointsByPrefix.put(anEntryPoint.getDesignator(), validationEntryPoint); } assertPrefixContentualUniqueness(config.getEntryPoints()); this.entryPoint = null; } else { RbfEntryPoint configuredEntryPoint = config.getEntryPoints().iterator().next(); Validator validator = traversingValidatorFactory.create(configuredEntryPoint.getDataTypeName(), configuredEntryPoint.getValidator()); this.entryPoint = new RbfEntryPoint(configuredEntryPoint.getDataTypeName(), configuredEntryPoint .getDesignator(), validator); Class objectType = getObjectType(entryPoint.getDataTypeName()); this.entryPointsByObjectType.put(objectType, entryPoint); this.entryPointsByPrefix = null; } } /** * {@inheritDoc} */ public final S createSerializer() { return createSerializer(this.config, this.entryPointsByObjectType); } /** * {@inheritDoc} */ public final D createDeserializer() { if (this.withPrefix) { return createDeserializer(this.config, this.entryPointsByPrefix); } else { return createDeserializer(this.config, this.entryPoint); } } /** * Returns true if prefixes are used and false otherwise. * * @return true if prefixes are used; otherwise false */ public boolean withPrefixes() { return prefixRequired(this.config.getEntryPoints()); } /** * Creates a new Serializer. * * @param config the configuration * @param entryPointsByObjectType a map from object types to entry points. * @return a Serializer */ protected abstract S createSerializer(C config, Map, RbfEntryPoint> entryPointsByObjectType); /** * Creates a new Deserializer. * * @param config the configuration * @param entryPoint the entry point * @return a Deserializer */ protected abstract D createDeserializer(C config, RbfEntryPoint entryPoint); /** * Creates a new ADeserializer. * * @param config the configuration * @param entryPointsByPrefix a map from prefixes to entry points * @return a Deserializer */ protected abstract D createDeserializer(C config, Map entryPointsByPrefix); /** * Returns true if and only if a prefix is required for the given entry points. * * @param entryPoints the entry points * @return true, if a prefix is required; false otherwise. */ protected final boolean prefixRequired(Collection entryPoints) { if (entryPoints.size() > 1) { return true; } else { String prefix = entryPoints.iterator().next().getDesignator(); return prefix != null && prefix.length() > 0; } } private Class getObjectType(String dataTypeName) { TypeMapping typeMapping = this.config.getTypeMappingRegistry().get(dataTypeName); if (typeMapping == null) { throw new IOFactoryException("Unknown data type: " + dataTypeName); } return typeMapping.getObjectType(); } private void assertPrefixDeclared(RbfEntryPoint entryPoint, Class objectType) { String prefix = entryPoint.getDesignator(); if (prefix == null || prefix.length() == 0) { throw new IOFactoryException("prefix not given but required for object type " + objectType.getName()); } } /** * Assert that all prefixes are contextual unique. *

* Suppose a tree of prefix where
* 1. the root is an artificial prefix which is always unique
* 2. the ordered children of the root are the prefixes of the entry points in their respective order
* 3. the ordered children of a prefix n which is not covered by 1. or 2. is the ordered list of prefixes * associated with the sub records or sub record list items of the complex type associated with the prefix n. * Note that there is no prefix associated with a sub record list but with the list items. *

* For a given prefix n the set S(n) is defined as the sibling prefixes "to the left" of n as well as their * descendants. Let further p(n) denote the parent of n. *

* Then a prefix n is called "contextual unique" if n != p(n) and n is not contained in S(n). * * @param entryPoints the entry points. */ private void assertPrefixContentualUniqueness(Collection entryPoints) { Set usedPrefixes = new HashSet(); for (RbfEntryPoint anEntryPoint : entryPoints) { assertPrefixContextualUniqueness(anEntryPoint.getDesignator(), anEntryPoint.getDataTypeName(), null, usedPrefixes); } } private void assertPrefixContextualUniqueness(String prefix, String dataTypeName, String parentPrefix, Set siblingUsedPrefixes) { if (siblingUsedPrefixes.contains(prefix) || (parentPrefix != null && parentPrefix.equals(prefix))) { throw new IOFactoryException("The prefix " + prefix + " is not contextual unique. The context is defined by the following list: " + siblingUsedPrefixes); } Set childrenUsedPrefixes = new HashSet(); TypeMapping typeMapping = this.config.getTypeMappingRegistry().get(dataTypeName); if (typeMapping instanceof RbfComplexTypeMapping) { RbfComplexTypeMapping complexTypeMapping = (RbfComplexTypeMapping) typeMapping; for (String fieldName : complexTypeMapping.getFieldNames(RbfNodeType.RECORD)) { RecordMapping recordMapping = complexTypeMapping.getNodeMapping(fieldName, Object.class); assertPrefixContextualUniqueness(recordMapping.getNodeDescriptor().getPrefix(), recordMapping .getDataTypeName(), prefix, childrenUsedPrefixes); } childrenUsedPrefixes.add(prefix); } if (typeMapping instanceof RbfListTypeMapping) { RbfListTypeMapping listTypeMapping = (RbfListTypeMapping) typeMapping; for (RecordMapping recordMapping : listTypeMapping.getNodeMappings()) { assertPrefixContextualUniqueness(recordMapping.getNodeDescriptor().getPrefix(), recordMapping .getDataTypeName(), parentPrefix, childrenUsedPrefixes); } // note: the prefix for a record mapping for a list type mapping is always null } siblingUsedPrefixes.addAll(childrenUsedPrefixes); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy