org.smooks.cartridges.javabean.BeanInstanceCreator Maven / Gradle / Ivy
The newest version!
/*-
* ========================LICENSE_START=================================
* smooks-javabean-cartridge
* %%
* Copyright (C) 2020 Smooks
* %%
* Licensed under the terms of the Apache License Version 2.0, or
* the GNU Lesser General Public License version 3.0 or later.
*
* SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-or-later
*
* ======================================================================
*
* 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.
*
* ======================================================================
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* =========================LICENSE_END==================================
*/
package org.smooks.cartridges.javabean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smooks.api.ApplicationContext;
import org.smooks.api.ExecutionContext;
import org.smooks.api.SmooksConfigException;
import org.smooks.api.SmooksException;
import org.smooks.api.bean.context.BeanContext;
import org.smooks.api.bean.lifecycle.BeanLifecycle;
import org.smooks.api.bean.repository.BeanId;
import org.smooks.api.delivery.fragment.Fragment;
import org.smooks.api.delivery.ordering.Producer;
import org.smooks.api.lifecycle.ContentDeliveryConfigLifecycle;
import org.smooks.api.lifecycle.PostFragmentLifecycle;
import org.smooks.api.resource.config.Parameter;
import org.smooks.api.resource.config.ResourceConfig;
import org.smooks.api.resource.visitor.VisitAfterReport;
import org.smooks.api.resource.visitor.VisitBeforeReport;
import org.smooks.api.resource.visitor.sax.ng.AfterVisitor;
import org.smooks.api.resource.visitor.sax.ng.BeforeVisitor;
import org.smooks.assertion.AssertArgument;
import org.smooks.cartridges.javabean.binding.model.ModelSet;
import org.smooks.cartridges.javabean.ext.BeanConfigUtil;
import org.smooks.cartridges.javabean.factory.Factory;
import org.smooks.cartridges.javabean.factory.FactoryDefinitionParser.FactoryDefinitionParserFactory;
import org.smooks.engine.bean.lifecycle.DefaultBeanContextLifecycleEvent;
import org.smooks.engine.delivery.fragment.NodeFragment;
import org.smooks.engine.expression.MVELExpressionEvaluator;
import org.w3c.dom.Element;
import jakarta.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Bean instance creator visitor class.
*
*
* @author [email protected]
*/
@VisitBeforeReport(summary = "Created ${resource.parameters.beanId!'undefined'} bean instance. Associated lifecycle if wired to another bean.",
detailTemplate = "reporting/BeanInstanceCreatorReport_Before.html")
@VisitAfterReport(condition = "parameters.containsKey('setOn') || parameters.beanClass.value.endsWith('[]')",
summary = "Ended bean lifecycle. Set bean on any targets.",
detailTemplate = "reporting/BeanInstanceCreatorReport_After.html")
public class BeanInstanceCreator implements BeforeVisitor, AfterVisitor, Producer, PostFragmentLifecycle, ContentDeliveryConfigLifecycle {
protected static final Logger LOGGER = LoggerFactory.getLogger(BeanInstanceCreator.class);
public static final String INIT_VAL_EXPRESSION = "initValExpression";
protected String id;
@Inject
@Named("beanId")
protected String beanIdName;
@Inject
@Named(BeanConfigUtil.BEAN_CLASS_CONFIG)
protected Optional beanClassName;
@Inject
@Named("beanFactory")
protected Optional beanFactoryDefinition;
@Inject
protected Boolean retain = true;
@Inject
protected ResourceConfig config;
@Inject
protected ApplicationContext applicationContext;
protected BeanRuntimeInfo beanRuntimeInfo;
protected BeanId beanId;
protected MVELExpressionEvaluator initValsExpression;
protected Factory> factory;
/**
* Public default constructor.
*/
public BeanInstanceCreator() {
}
/**
* Public default constructor.
*
* @param beanId The beanId under which the bean instance is registered in the bean context.
* @param beanClass The bean runtime class.
*/
public BeanInstanceCreator(String beanId, Class> beanClass) {
this(beanId, beanClass, null);
}
/**
* Public default constructor.
*
* @param beanId The beanId under which the bean instance is registered in the bean context.
* @param beanClass The bean runtime class.
*/
public BeanInstanceCreator(String beanId, Class beanClass, Factory extends T> factory) {
AssertArgument.isNotNull(beanId, "beanId");
AssertArgument.isNotNull(beanClass, "beanClass");
this.beanIdName = beanId;
this.beanClassName = Optional.of(toClassName(beanClass));
this.factory = factory;
}
/**
* Get the beanId of this Bean configuration.
*
* @return The beanId of this Bean configuration.
*/
public String getBeanId() {
return beanIdName;
}
public ResourceConfig getConfig() {
return config;
}
/**
* Set the resource configuration on the bean populator.
*
* @throws org.smooks.api.SmooksConfigException Incorrectly configured resource.
*/
@PostConstruct
public void postConstruct() throws SmooksConfigException {
buildId();
beanId = applicationContext.getBeanIdStore().register(beanIdName);
beanId.setCreateResourceConfiguration(config);
if (!beanFactoryDefinition.orElse("").isEmpty()) {
String alias = null;
String definition = beanFactoryDefinition.get();
if (!definition.contains("#")) {
try {
URI definitionURI = new URI(definition);
if (definitionURI.getScheme() == null) {
// Default it to MVEL...
definition = "mvel:" + definition;
}
} catch (URISyntaxException e) {
// Let it run...
}
}
int aliasSplitterIndex = definition.indexOf(':');
if (aliasSplitterIndex > 0) {
alias = definition.substring(0, aliasSplitterIndex);
definition = definition.substring(aliasSplitterIndex + 1);
}
factory = FactoryDefinitionParserFactory.getInstance(alias, applicationContext).parse(definition);
}
beanRuntimeInfo = BeanRuntimeInfo.getBeanRuntimeInfo(beanIdName, beanClassName.orElse(null), applicationContext);
if (factory == null) {
checkForDefaultConstructor();
} else if (beanRuntimeInfo.getClassification() == BeanRuntimeInfo.Classification.ARRAY_COLLECTION) {
throw new SmooksConfigException("Using a factory with an array is not supported");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("BeanInstanceCreator created for [" + beanIdName + "]. BeanRuntimeInfo: " + beanRuntimeInfo);
}
List> initValExpressions = config.getParameters(INIT_VAL_EXPRESSION);
if (initValExpressions != null && !initValExpressions.isEmpty()) {
StringBuilder initValsExpressionString = new StringBuilder();
for (Parameter> initValExpression : initValExpressions) {
initValsExpressionString.append(initValExpression.getValue());
initValsExpressionString.append("\n");
}
initValsExpression = new MVELExpressionEvaluator();
initValsExpression.setExpression(initValsExpressionString.toString());
}
}
/**
* Get the bean runtime information.
*
* @return The bean runtime information.
*/
public BeanRuntimeInfo getBeanRuntimeInfo() {
return beanRuntimeInfo;
}
protected void buildId() {
StringBuilder idBuilder = new StringBuilder();
idBuilder.append(BeanInstanceCreator.class.getName());
idBuilder.append("#");
idBuilder.append(beanIdName);
id = idBuilder.toString();
}
@Override
public void visitBefore(Element element, ExecutionContext executionContext) throws SmooksException {
createAndSetBean(executionContext, new NodeFragment(element));
}
/* (non-Javadoc)
* @see org.smooks.delivery.sax.SAXVisitAfter#visitAfter(org.smooks.delivery.sax.SAXElement, org.smooks.api.ExecutionContext)
*/
@Override
public void visitAfter(Element element, ExecutionContext executionContext) throws SmooksException {
visitAfter(executionContext, new NodeFragment(element));
}
public void visitAfter(ExecutionContext executionContext, Fragment source) {
BeanRuntimeInfo.Classification thisBeanType = beanRuntimeInfo.getClassification();
boolean isBeanTypeArray = (thisBeanType == BeanRuntimeInfo.Classification.ARRAY_COLLECTION);
BeanContext beanContext = executionContext.getBeanContext();
beanContext.setBeanInContext(beanId, false);
if (isBeanTypeArray) {
Object bean = beanContext.getBean(beanId);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Converting bean [" + beanIdName + "] to an array and rebinding to context.");
}
bean = convert(executionContext, bean, source);
}
}
protected Object convert(ExecutionContext executionContext, Object bean, Fragment source) {
bean = BeanUtils.convertListToArray((List>) bean, beanRuntimeInfo.getArrayType());
executionContext.getBeanContext().changeBean(beanId, bean, source);
return bean;
}
protected void createAndSetBean(ExecutionContext executionContext, Fragment source) {
Object bean;
BeanContext beanContext = executionContext.getBeanContext();
bean = createBeanInstance(executionContext);
executionContext.getBeanContext().notifyObservers(new DefaultBeanContextLifecycleEvent(executionContext, source, BeanLifecycle.START_FRAGMENT, beanId, bean));
if (initValsExpression != null) {
initValsExpression.exec(bean);
}
beanContext.setBeanInContext(beanId, false);
beanContext.addBean(beanId, bean, source);
beanContext.setBeanInContext(beanId, true);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Bean [" + beanIdName + "] instance created.");
}
}
/**
* Create a new bean instance, generating relevant configuration exceptions.
*
* @return A new bean instance.
*/
protected Object createBeanInstance(ExecutionContext executionContext) {
Object bean;
if (factory == null) {
try {
bean = beanRuntimeInfo.getPopulateType().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new SmooksConfigException("Unable to create bean instance [" + beanIdName + ":" + beanRuntimeInfo.getPopulateType().getName() + "].", e);
}
} else {
try {
bean = factory.create(executionContext);
} catch (RuntimeException e) {
throw new SmooksConfigException("The factory was unable to create the bean instance [" + beanIdName + "] using the factory '" + factory + "'.", e);
}
}
return bean;
}
public Set> getProducts() {
return Stream.of(beanIdName).collect(Collectors.toSet());
}
protected String getId() {
return id;
}
@Override
public String toString() {
return getId();
}
protected String toClassName(Class> beanClass) {
if (!beanClass.isArray()) {
return beanClass.getName();
} else {
return beanClass.getComponentType().getName() + "[]";
}
}
/**
* Checks if the class has a default constructor
*/
protected void checkForDefaultConstructor() {
try {
beanRuntimeInfo.getPopulateType().getConstructor();
} catch (NoSuchMethodException e) {
throw new SmooksConfigException("Invalid Smooks bean configuration. Bean class " + beanRuntimeInfo.getPopulateType().getName() + " doesn't have a public default constructor.");
}
}
@Override
public void onPostFragment(Fragment fragment, ExecutionContext executionContext) {
BeanContext beanContext = executionContext.getBeanContext();
Object bean = beanContext.getBean(beanId);
beanContext.notifyObservers(new DefaultBeanContextLifecycleEvent(executionContext, fragment, BeanLifecycle.END_FRAGMENT, beanId, bean));
if (!retain) {
beanContext.removeBean(beanId, null);
}
}
@Override
public void onContentHandlersCreated() {
}
@Override
public void onContentDeliveryBuilderCreated() {
ModelSet.build(applicationContext);
}
@Override
public void onContentDeliveryConfigCreated() {
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy