/*
* Copyright 2004-2012 the Seasar Foundation and the Others.
*
* 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 org.seasar.mayaa.impl.builder.library;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.seasar.mayaa.builder.library.LibraryDefinition;
import org.seasar.mayaa.builder.library.ProcessorDefinition;
import org.seasar.mayaa.builder.library.PropertyDefinition;
import org.seasar.mayaa.builder.library.PropertySet;
import org.seasar.mayaa.builder.library.converter.PropertyConverter;
import org.seasar.mayaa.engine.processor.InformalPropertyAcceptable;
import org.seasar.mayaa.engine.processor.TemplateProcessor;
import org.seasar.mayaa.engine.processor.VirtualPropertyAcceptable;
import org.seasar.mayaa.engine.specification.NodeAttribute;
import org.seasar.mayaa.engine.specification.PrefixAwareName;
import org.seasar.mayaa.engine.specification.QName;
import org.seasar.mayaa.engine.specification.SpecificationNode;
import org.seasar.mayaa.engine.specification.URI;
import org.seasar.mayaa.impl.CONST_IMPL;
import org.seasar.mayaa.impl.engine.specification.SpecificationUtil;
import org.seasar.mayaa.impl.util.ObjectUtil;
import org.seasar.mayaa.impl.util.StringUtil;
import org.seasar.mayaa.impl.util.collection.NullIterator;
/**
* @author Masataka Kurihara (Gluegent, Inc.)
*/
public class ProcessorDefinitionImpl extends PropertySetImpl
implements ProcessorDefinition, CONST_IMPL {
private static final long serialVersionUID = -9158405427849768423L;
private static final Log LOG =
LogFactory.getLog(ProcessorDefinitionImpl.class);
private Class _processorClass;
private List _propertySetRefs;
public void setProcessorClass(Class processorClass) {
if (processorClass == null
|| TemplateProcessor.class.isAssignableFrom(
processorClass) == false) {
throw new IllegalArgumentException();
}
_processorClass = processorClass;
}
public Class getProcessorClass() {
return _processorClass;
}
public void addPropertySetRef(
String name, String systemID, int lineNumber) {
if (StringUtil.isEmpty(name)) {
throw new IllegalArgumentException();
}
if (_propertySetRefs == null) {
_propertySetRefs = new ArrayList();
}
if (_propertySetRefs.contains(name)) {
if (LOG.isWarnEnabled()) {
String line = Integer.toString(lineNumber);
LOG.warn(StringUtil.getMessage(
ProcessorDefinitionImpl.class, 1, name, systemID, line));
}
} else {
_propertySetRefs.add(
new PropertySetRef(name, systemID, lineNumber));
}
}
public Iterator iteratePropertySets() {
if (_propertySetRefs == null) {
return NullIterator.getInstance();
}
Iterator it = _propertySetRefs.iterator();
return new PropertySetIterator(it, getLibraryDefinition());
}
protected TemplateProcessor newInstance() {
return (TemplateProcessor) ObjectUtil.newInstance(_processorClass);
}
protected PrefixAwareName getPrefixAwareName(
SpecificationNode injected, String propertyName) {
QName qName = SpecificationUtil.createQName(
injected.getQName().getNamespaceURI(), propertyName);
// メモリリークを起こす可能性があるので参照を断つ
NodeAttribute attr = injected.getAttribute(qName);
PrefixAwareName name = SpecificationUtil.createPrefixAwareName(
attr.getQName(), attr.getPrefix());
return name;
}
protected void settingProperty(
SpecificationNode original, SpecificationNode injected,
TemplateProcessor processor, PropertyDefinition property) {
Object value =
property.createProcessorProperty(this, processor, original, injected);
if (value != null) {
String propertyImplName = property.getImplName();
Class processorClass = getProcessorClass();
if (ObjectUtil.hasProperty(processorClass, propertyImplName)) {
// prefixが付いていない限りoriginalを引き継がせる
if (value instanceof PrefixAwareName) {
value = settingDefaultNamespace(
original, (PrefixAwareName) value);
}
ObjectUtil.setProperty(processor, propertyImplName, value);
} else if (processor instanceof VirtualPropertyAcceptable) {
VirtualPropertyAcceptable acceptable =
(VirtualPropertyAcceptable) processor;
if (value instanceof Serializable) {
PrefixAwareName name =
getPrefixAwareName(injected, property.getName());
acceptable.addVirtualProperty(name, (Serializable) value);
} else {
if (LOG.isWarnEnabled()) {
LOG.warn(StringUtil.getMessage(
ProcessorDefinitionImpl.class, 3,
processorClass.getName(), propertyImplName,
value.getClass().getName()));
}
}
} else {
if (LOG.isWarnEnabled()) {
LOG.warn(StringUtil.getMessage(
ProcessorDefinitionImpl.class, 2,
processorClass.getName(), propertyImplName));
}
}
}
}
protected PrefixAwareName settingDefaultNamespace(
SpecificationNode original, PrefixAwareName value) {
QName valueName = value.getQName();
if (URI_MAYAA.equals(valueName.getNamespaceURI())) {
if (StringUtil.isEmpty(value.getPrefix())) {
QName qName = SpecificationUtil.createQName(
original.getDefaultNamespaceURI(),
valueName.getLocalName());
value = SpecificationUtil.createPrefixAwareName(qName, "");
}
}
return value;
}
protected void settingPropertySet(
SpecificationNode original, SpecificationNode injected,
TemplateProcessor processor, PropertySet propertySet) {
for (Iterator it = propertySet.iteratePropertyDefinition(); it.hasNext();) {
PropertyDefinition property = (PropertyDefinition) it.next();
settingProperty(original, injected, processor, property);
}
}
protected void settingInformalProperties(SpecificationNode injected,
InformalPropertyAcceptable acceptable) {
URI injectedNS = injected.getQName().getNamespaceURI();
for (Iterator it = injected.iterateAttribute(); it.hasNext();) {
NodeAttribute attr = (NodeAttribute) it.next();
if (contain(injectedNS, attr)) {
continue;
}
LibraryDefinition library = getLibraryDefinition();
Class propertyClass = acceptable.getInformalPropertyClass();
PropertyConverter converter =
library.getPropertyConverter(propertyClass);
if (converter == null) {
throw new ConverterNotFoundException(
propertyClass.getName(), getSystemID(), getLineNumber());
}
Class expectedClass = acceptable.getInformalExpectedClass();
String value = attr.getValue();
Serializable property = converter.convert(attr, value, expectedClass);
if (property == null) {
throw new ConverterOperationException(converter, value);
}
// メモリリークを起こす可能性があるので参照を断つ
PrefixAwareName name = SpecificationUtil.createPrefixAwareName(
attr.getQName(), attr.getPrefix());
acceptable.addInformalProperty(name, property);
}
}
public TemplateProcessor createTemplateProcessor(
SpecificationNode original, SpecificationNode injected) {
if (injected == null) {
throw new IllegalArgumentException();
}
TemplateProcessor processor = newInstance();
processor.setProcessorDefinition(this);
settingPropertySet(original, injected, processor, this);
for (Iterator it = iteratePropertySets(); it.hasNext();) {
PropertySet propertySet = (PropertySet) it.next();
settingPropertySet(original, injected, processor, propertySet);
}
if (processor instanceof InformalPropertyAcceptable) {
settingInformalProperties(
injected, (InformalPropertyAcceptable) processor);
}
return processor;
}
// support class ------------------------------------------------
protected static class PropertySetRef implements Serializable {
private static final long serialVersionUID = -3425332447146558868L;
private String _name;
private String _systemID;
private int _lineNumber;
public PropertySetRef(String name, String systemID, int lineNumber) {
if (StringUtil.isEmpty(name)
|| StringUtil.isEmpty(systemID) || lineNumber < 0) {
throw new IllegalArgumentException();
}
_name = name;
_systemID = systemID;
_lineNumber = lineNumber;
}
public String getName() {
return _name;
}
public String getSystemID() {
return _systemID;
}
public int getLineNumber() {
return _lineNumber;
}
}
protected static class PropertySetIterator implements Iterator {
private Iterator _it;
private LibraryDefinition _library;
public PropertySetIterator(Iterator it, LibraryDefinition library) {
if (it == null || library == null) {
throw new IllegalArgumentException();
}
_it = it;
_library = library;
}
public boolean hasNext() {
return _it.hasNext();
}
public Object next() {
PropertySetRef ref = (PropertySetRef) _it.next();
PropertySet propertySet = _library.getPropertySet(ref.getName());
if (propertySet == null) {
throw new PropertySetNotFoundException(ref.getName(),
ref.getSystemID(), ref.getLineNumber());
}
return propertySet;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}