com.tcdng.unify.core.UnifyContainer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of unify-core Show documentation
Show all versions of unify-core Show documentation
Unify Framework: Core Components
/*
* Copyright 2018-2020 The Code Department.
*
* 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 com.tcdng.unify.core;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.RollingFileAppender;
import com.tcdng.unify.core.annotation.Broadcast;
import com.tcdng.unify.core.annotation.Component;
import com.tcdng.unify.core.annotation.Configurable;
import com.tcdng.unify.core.annotation.Periodic;
import com.tcdng.unify.core.annotation.PeriodicType;
import com.tcdng.unify.core.annotation.Plugin;
import com.tcdng.unify.core.application.BootService;
import com.tcdng.unify.core.business.BusinessLogicUnit;
import com.tcdng.unify.core.business.BusinessService;
import com.tcdng.unify.core.business.internal.ProxyBusinessServiceGenerator;
import com.tcdng.unify.core.constant.AnnotationConstants;
import com.tcdng.unify.core.data.FactoryMap;
import com.tcdng.unify.core.data.LocaleFactoryMaps;
import com.tcdng.unify.core.format.DateTimeFormatter;
import com.tcdng.unify.core.logging.AbstractLog4jLogger;
import com.tcdng.unify.core.logging.DummyEventLogger;
import com.tcdng.unify.core.logging.Logger;
import com.tcdng.unify.core.logging.LoggingLevel;
import com.tcdng.unify.core.message.ResourceBundles;
import com.tcdng.unify.core.system.ClusterService;
import com.tcdng.unify.core.system.Command;
import com.tcdng.unify.core.system.UserSessionManager;
import com.tcdng.unify.core.task.TaskManager;
import com.tcdng.unify.core.task.TaskMonitor;
import com.tcdng.unify.core.upl.UplCompiler;
import com.tcdng.unify.core.upl.UplComponent;
import com.tcdng.unify.core.upl.UplElementAttributes;
import com.tcdng.unify.core.util.AnnotationUtils;
import com.tcdng.unify.core.util.DataUtils;
import com.tcdng.unify.core.util.IOUtils;
import com.tcdng.unify.core.util.ImageUtils;
import com.tcdng.unify.core.util.NameUtils;
import com.tcdng.unify.core.util.ReflectUtils;
import com.tcdng.unify.core.util.StringUtils;
import com.tcdng.unify.core.util.ThreadUtils;
import com.tcdng.unify.core.util.TokenUtils;
import com.tcdng.unify.core.util.UnifyConfigUtils;
/**
* Represents a container for unify components.
*
* @author Lateef Ojulari
* @since 1.0
*/
public class UnifyContainer {
public static final String DEFAULT_APPLICATION_BANNER = "banner/banner.txt";
public static final short DEFAULT_COMMAND_PORT = 4242;
public static final int DEFAULT_APPLICATION_QUERY_LIMIT = 10000;
public static final int DEFAULT_APPLICATION_SESSION_TIMEOUT = 600;
private static final long PERIODIC_EXECUTION_INITIAL_DELAY = 200;
private static final long COMMAND_THREAD_RATE = 1000;
private static ThreadLocal initializationTrailThreadLocal =
new ThreadLocal() {
@Override
protected InitializationTrail initialValue() {
return new InitializationTrail();
}
};
private UnifyContainerEnvironment unifyContainerEnvironment;
private Map internalUnifyComponentInfos;
private Map internalResolutionMap;
private Map unifySettings;
private Map aliases;
private List staticSettings;
private RequestContextManager requestContextManager;
private ApplicationContext applicationContext;
private BootService applicationBootService;
private ClusterService clusterService;
private UplCompiler uplCompiler;
private UserSessionManager userSessionManager;
private ResourceBundles messages;
private Logger logger;
private FactoryMap componentContextMap;
private FactoryMap singletonComponentMap;
private LocaleFactoryMaps cachedLocaleUplComponentMap;
private List periodicTaskMonitorList;
private List singletonTerminationList;
private Set interfaces;
private Queue containerCommandQueue;
private Map broadcastInfoMap;
private Map, List> namelessConfigurableSuggestions;
private String nodeId;
private String deploymentVersion;
private String hostAddress;
private String hostHome;
private String accessKey;
private Date startTime;
private Locale applicationLocale;
private TimeZone applicationTimeZone;
private boolean toConsole;
private boolean productionMode;
private boolean clusterMode;
private boolean deploymentMode;
private boolean started;
private boolean shutdown;
public UnifyContainer() {
accessKey = UUID.randomUUID().toString();
internalUnifyComponentInfos = new ConcurrentHashMap();
periodicTaskMonitorList = new ArrayList();
singletonTerminationList = new ArrayList();
interfaces = new HashSet();
containerCommandQueue = new ConcurrentLinkedQueue();
broadcastInfoMap = new HashMap();
namelessConfigurableSuggestions = new HashMap, List>();
componentContextMap = new FactoryMap() {
@Override
protected UnifyComponentContext create(String name, Object... params) throws Exception {
return new UnifyComponentContext(applicationContext, getLogger(name), name);
}
};
singletonComponentMap = new FactoryMap() {
// Added to handle cyclic dependency in singletons
private Map singletonMap = new HashMap();
@Override
public UnifyComponent get(String name, Object... params) throws UnifyException {
UnifyComponent unifyComponent = singletonMap.get(name);
if (unifyComponent == null) {
return super.get(name, params);
}
return unifyComponent;
}
@Override
protected UnifyComponent create(String name, Object... params) throws Exception {
UnifyComponentConfig unifyComponentConfig = (UnifyComponentConfig) params[0];
UplElementAttributes uplElementAttributes = (UplElementAttributes) params[1];
UnifyComponent unifyComponent = unifyComponentConfig.getType().newInstance();
singletonMap.put(name, unifyComponent);
initializeComponent(unifyComponentConfig, null, unifyComponent, uplElementAttributes);
singletonTerminationList.add(0, unifyComponent);
return unifyComponent;
}
};
cachedLocaleUplComponentMap = new LocaleFactoryMaps() {
@Override
protected UplComponent createObject(Locale locale, String descriptor, Object... params) throws Exception {
UplComponent localeComponent = getUplComponent(locale, descriptor, false);
return localeComponent;
}
};
}
/**
* Starts the container using supplied configuration.
*
* @param uce
* the environment object
* @param ucc
* the configuration used for initialization
* @throws UnifyException
* if container is already started. If an error occurs.
*/
@SuppressWarnings("unchecked")
public void startup(UnifyContainerEnvironment uce, UnifyContainerConfig ucc) throws UnifyException {
if (started || shutdown) {
throw new UnifyException(UnifyCoreErrorConstants.CONTAINER_ALREADY_INITIALIZED);
}
// Environment
unifyContainerEnvironment = uce;
try {
InetAddress inetAddress = InetAddress.getLocalHost();
hostAddress = inetAddress.getHostAddress();
hostHome = inetAddress.getHostName();
} catch (UnknownHostException e) {
throw new UnifyException(e, UnifyCoreErrorConstants.CONTAINER_ERROR);
}
deploymentVersion = ucc.getDeploymentVersion();
clusterMode = ucc.isClusterMode();
productionMode = ucc.isProductionMode();
deploymentMode = ucc.isDeploymentMode();
unifySettings = ucc.getProperties();
aliases = ucc.getAliases();
staticSettings = ucc.getStaticSettings();
nodeId = ucc.getNodeId();
if (nodeId == null) {
throw new UnifyException(UnifyCoreErrorConstants.CONTAINER_NODEID_REQUIRED);
}
toConsole = true;
if (unifySettings.get(UnifyCorePropertyConstants.APPLICATION_TOCONSOLE) != null) {
toConsole = Boolean.valueOf(
String.valueOf(unifySettings.get(UnifyCorePropertyConstants.APPLICATION_TOCONSOLE)));
}
// Banner
List banner = getApplicationBanner();
if (!banner.isEmpty()) {
for (String line : banner) {
toConsole(line);
}
}
String lineSeparator = System.getProperty("line.separator");
applicationContext = new ApplicationContext(this, getApplicationLocale(), getApplicationTimeZone(),
lineSeparator != null ? lineSeparator : "\n");
long startTimeMillis = System.currentTimeMillis();
initializeContainerMessages();
initializeContainerLogger();
toConsole("Container initialization started...");
toConsole("Validating and loading configuration...");
for (UnifyComponentConfig unifyComponentConfig : ucc.getComponentConfigs()) {
// Validate configuration
Class> type = unifyComponentConfig.getType();
for (String property : unifyComponentConfig.getSettings().getPropertyNames()) {
Field field = ReflectUtils.getField(type, property);
if (!field.isAnnotationPresent(Configurable.class)) {
throw new UnifyException(UnifyCoreErrorConstants.COMPONENT_PROPERTY_NOT_CONFIGURABLE,
unifyComponentConfig.getName(), type, property);
} else if (UnifyComponent.class.isAssignableFrom(field.getType())) {
// Setup nameless references
Configurable ca = field.getAnnotation(Configurable.class);
if (ca.value() == AnnotationConstants.NONE || ca.values().length == 0) {
if (!namelessConfigurableSuggestions.containsKey(field.getType())) {
namelessConfigurableSuggestions.put((Class extends UnifyComponent>) field.getType(),
null);
}
}
}
}
// Create internal information objects
internalUnifyComponentInfos.put(unifyComponentConfig.getName(),
new InternalUnifyComponentInfo(unifyComponentConfig));
}
logDebug("Detecting and replacing customized components...");
// Resolve customization
List customizationSuffixList = DataUtils.convert(ArrayList.class, String.class,
getSetting(UnifyCorePropertyConstants.APPLICATION_CUSTOMIZATION), null);
internalResolutionMap =
UnifyConfigUtils.resolveConfigurationOverrides(internalUnifyComponentInfos, customizationSuffixList);
// Detect business components
logDebug("Detecting business service components...");
Map> componentPeriodMethodMap = new HashMap>();
Map> componentPluginSocketsMap = new HashMap>();
List managedBusinessServiceConfigList = new ArrayList();
for (Map.Entry entry : internalUnifyComponentInfos.entrySet()) {
InternalUnifyComponentInfo iuci = entry.getValue();
// Fetch periodic method information
Map periodicMethodMap = new HashMap();
Set pluginSockets = new HashSet();
Method[] methods = iuci.getType().getMethods();
for (Method method : methods) {
// Periodic methods
Periodic pa = method.getAnnotation(Periodic.class);
if (pa != null) {
if (iuci.isSingleton() && void.class.equals(method.getReturnType())
&& method.getParameterTypes().length == 1
&& method.getParameterTypes()[0].equals(TaskMonitor.class)) {
periodicMethodMap.put(method.getName(), pa);
} else {
throw new UnifyException(UnifyCoreErrorConstants.COMPONENT_INVALID_PERIOD_METHOD,
iuci.getName(), method.getName());
}
}
// Broadcast methods
Broadcast ba = method.getAnnotation(Broadcast.class);
if (ba != null) {
if (iuci.isSingleton() && void.class.equals(method.getReturnType())
&& method.getParameterTypes().length == 1
&& method.getParameterTypes()[0].equals(String[].class)) {
String name = NameUtils.getComponentMethodName(iuci.getName(), method.getName());
broadcastInfoMap.put(name, new BroadcastInfo(iuci.getName(), method.getName()));
} else {
throw new UnifyException(UnifyCoreErrorConstants.COMPONENT_INVALID_BROADCAST_METHOD,
iuci.getName(), method.getName());
}
}
}
if (!periodicMethodMap.isEmpty()) {
logDebug("Periodic methods detected for component '" + iuci.getName() + "'.");
componentPeriodMethodMap.put(iuci.getName(), periodicMethodMap);
}
if (!pluginSockets.isEmpty()) {
logDebug("Plug-in sockets detected for component '" + iuci.getName() + "'.");
componentPluginSocketsMap.put(iuci.getName(), pluginSockets);
}
if (ReflectUtils.isInterface(iuci.getType(), BusinessService.class)) {
logDebug("Business component '" + iuci.getName() + "' detected.");
managedBusinessServiceConfigList.add(iuci.getUnifyComponentConfig());
}
}
// Detect business logic plug-ins
logDebug("Detecting business logic plugins...");
Map>> allPluginsBySocketMap =
new HashMap>>();
for (Map.Entry entry : internalUnifyComponentInfos.entrySet()) {
InternalUnifyComponentInfo iuci = entry.getValue();
// Check if component is a BLU plug-in
Plugin pla = iuci.getType().getAnnotation(Plugin.class);
if (pla != null) {
if (BusinessLogicUnit.class.isAssignableFrom(iuci.getType())) {
InternalUnifyComponentInfo busServInfo = internalUnifyComponentInfos.get(pla.target());
if (busServInfo == null) {
throw new UnifyException(UnifyCoreErrorConstants.BUSINESSLOGIC_PLUGIN_TARGET_UNKNOWN,
iuci.getName(), pla.target());
}
if (!BusinessService.class.isAssignableFrom(busServInfo.getType())) {
throw new UnifyException(UnifyCoreErrorConstants.BUSINESSLOGIC_PLUGIN_TARGET_NON_BUSINESSMODULE,
iuci.getName(), pla.target());
}
Method method = null;
try {
method = busServInfo.getType().getMethod(pla.method(), pla.paramTypes());
} catch (Exception e) {
throw new UnifyException(UnifyCoreErrorConstants.BUSINESSLOGIC_PLUGIN_TARGET_NON_SOCKET,
iuci.getName(), pla.method(), pla.target(), e);
}
Map> map = allPluginsBySocketMap.get(pla.target());
if (map == null) {
map = new HashMap>();
allPluginsBySocketMap.put(pla.target(), map);
}
String methodSig = ReflectUtils.getMethodSignature(busServInfo.getName(), method);
List list = map.get(methodSig);
if (list == null) {
list = new ArrayList();
map.put(methodSig, list);
}
list.add(new UnifyPluginInfo(iuci.getName(), pla.type()));
}
}
}
// Set some system defaults
if (!internalUnifyComponentInfos.containsKey(ApplicationComponents.APPLICATION_EVENTSLOGGER)) {
UnifyComponentConfig internalComponentConfig =
new UnifyComponentConfig(ApplicationComponents.APPLICATION_EVENTSLOGGER, "Application Event Logger",
DummyEventLogger.class, true);
internalUnifyComponentInfos.put(internalComponentConfig.getName(),
new InternalUnifyComponentInfo(internalComponentConfig));
}
// Set nameless suggestions
logDebug("Setting nameless suggestions...");
for (Map.Entry, List> entry : namelessConfigurableSuggestions
.entrySet()) {
entry.setValue(getComponentNames(entry.getKey()));
}
// Initialization
started = true;
try {
requestContextManager =
(RequestContextManager) getComponent(ApplicationComponents.APPLICATION_REQUESTCONTEXTMANAGER);
uplCompiler = (UplCompiler) getComponent(ApplicationComponents.APPLICATION_UPLCOMPILER);
// Generate and install proxy business service objects
logInfo("Generating and installing proxy business service objects...");
for (UnifyComponentConfig unifyComponentConfig : managedBusinessServiceConfigList) {
Map> pluginMap = allPluginsBySocketMap.get(unifyComponentConfig.getName());
if (pluginMap == null) {
pluginMap = Collections.emptyMap();
}
UnifyComponentConfig proxyUnifyComponentConfig =
generateInstallBusinessServiceProxyObjects(unifyComponentConfig, pluginMap);
InternalUnifyComponentInfo iuc = getInternalUnifyComponentInfo(proxyUnifyComponentConfig.getName());
iuc.setUnifyComponentConfig(proxyUnifyComponentConfig);
}
// Set proxy broadcast methods
logInfo("Setting broadcast proxy methods...");
for (BroadcastInfo broadcastInfo : broadcastInfoMap.values()) {
InternalUnifyComponentInfo iuc = getInternalUnifyComponentInfo(broadcastInfo.getComponentName());
Method method = ReflectUtils.getMethod(iuc.getType(), broadcastInfo.getMethodName(), String[].class);
broadcastInfo.setMethod(method);
}
logInfo("Generation and installation of proxy objects completed");
// Cluster manager
clusterService = (ClusterService) getComponent(ApplicationComponents.APPLICATION_CLUSTERSERVICE);
userSessionManager = (UserSessionManager) getComponent(ApplicationComponents.APPLICATION_USERSESSIONMANAGER);
// Initialize utilities
ImageUtils.scanForPlugins();
DataUtils.registerDefaultFormatters((DateTimeFormatter) getUplComponent(getApplicationLocale(), "!datetimeformat", false));
// Run application startup service
toConsole("Initializing application bootup service...");
String bootComponentName = (String) unifySettings.get(UnifyCorePropertyConstants.APPLICATION_BOOT);
if (bootComponentName == null) {
bootComponentName = ApplicationComponents.APPLICATION_DEFAULTBOOTSERVICE;
}
applicationBootService = (BootService) getComponent(bootComponentName);
applicationBootService.startup();
toConsole("Application bootup service initialization completed.");
// Initialize interfaces
logInfo("Initializing container interfaces...");
initializeInterfaces();
logInfo("Container interfaces initialization complete.");
// Schedule periodic tasks
logInfo("Scheduling periodic tasks...");
TaskManager taskManager = (TaskManager) getComponent(ApplicationComponents.APPLICATION_TASKMANAGER);
for (Map.Entry> entry1 : componentPeriodMethodMap.entrySet()) {
logInfo("Intializing component [{0}] with periodic methods...", entry1.getKey());
getComponent(entry1.getKey());
for (Map.Entry entry2 : entry1.getValue().entrySet()) {
Periodic pa = entry2.getValue();
PeriodicType periodicType = pa.value();
String taskStatusLoggerName = AnnotationUtils.getAnnotationString(pa.taskStatusLogger());
TaskMonitor taskMonitor = taskManager.schedulePeriodicExecution(periodicType, entry1.getKey(),
entry2.getKey(), taskStatusLoggerName, PERIODIC_EXECUTION_INITIAL_DELAY);
periodicTaskMonitorList.add(taskMonitor);
}
}
logInfo("Periodic task scheduling completed.");
// Open container interfaces to start servicing requests
openInterfaces();
// Start command processing thread
new CommandThread().start();
// Set start time to now
startTime = new Date();
// Container initialization completed
long startupTimeMillis = startTime.getTime() - startTimeMillis;
toConsole("Container initialization completed in " + startupTimeMillis + "ms.");
} catch (UnifyException ue) {
logError(ue);
throw ue;
}
}
/**
* Shuts down the container.
*/
public void shutdown() {
if (!shutdown) {
shutdown = true;
logInfo("Shutting down container...");
try {
closeInterfaces();
} catch (Exception e) {
}
for (TaskMonitor taskMonitor : new ArrayList(periodicTaskMonitorList)) {
taskMonitor.cancel();
while (taskMonitor.isRunning()) {
ThreadUtils.sleep(1000);
}
}
try {
applicationBootService.shutdown();
} catch (Exception e) {
}
for (UnifyComponent unifyComponent : new ArrayList(singletonTerminationList)) {
try {
unifyComponent.terminate();
} catch (Exception e) {
}
}
singletonTerminationList = null;
singletonComponentMap = null;
internalUnifyComponentInfos = null;
componentContextMap = null;
logInfo("Container shutdown completed.");
}
}
/**
* Gets the container's access key.
*
* @return the access key
*/
public String getAccessKey() {
return accessKey;
}
/**
* Gets current container information.
*
* @return the container information object
*/
public UnifyContainerInfo getInfo() {
List componentInfoList = new ArrayList();
for (InternalUnifyComponentInfo uici : internalUnifyComponentInfos.values()) {
List settingInfoList = new ArrayList();
UnifyComponentSettings unifyComponentSettings = uici.unifyComponentConfig.getSettings();
for (String name : unifyComponentSettings.getPropertyNames()) {
settingInfoList.add(unifyComponentSettings.getSetting(name));
}
componentInfoList.add(new UnifyComponentInfo(uici.getName(), uici.getOriginalType(),
uici.getFirstPassTime(), uici.getFirstFailTime(), uici.getLastPassTime(), uici.getLastFailTime(),
uici.getPassCount(), uici.getFailCount(), settingInfoList));
}
List interfaceInfoList = new ArrayList();
for (UnifyContainerInterface ui : interfaces) {
interfaceInfoList.add(new UnifyInterfaceInfo(ui.getName(), ui.getPort(), ui.isServicingRequests()));
}
List settingInfoList = new ArrayList();
for (Map.Entry entry : unifySettings.entrySet()) {
settingInfoList.add(new UnifyContainerSettingInfo(entry.getKey(), entry.getValue()));
}
Runtime runtime = Runtime.getRuntime();
long totalMemory = runtime.totalMemory();
long usedMemory = totalMemory - runtime.freeMemory();
return new UnifyContainerInfo((String) unifySettings.get(UnifyCorePropertyConstants.APPLICATION_NAME), nodeId,
deploymentVersion, hostAddress, hostHome, startTime, usedMemory, totalMemory, clusterMode,
productionMode, deploymentMode, componentInfoList, interfaceInfoList, settingInfoList);
}
/**
* Receives and processes a command.
*
* @param command
* the command to process
* @param params
* the command parameters
* @throws UnifyException
* if an error occurs
*/
public void command(String command, String... params) throws UnifyException {
try {
containerCommandQueue.offer(new ContainerCommand(command, params));
} catch (ClassCastException e) {
throw new UnifyException(e, UnifyCoreErrorConstants.COMPONENT_OPERATION_ERROR, "Unify Container");
}
}
public boolean isStarted() {
return started;
}
public boolean isShutdown() {
return shutdown;
}
/**
* Gets all component names with types that extend or implement specific
* component type.
*
* @param componentType
* the component type to match
* @return a list of component names that match with supplied type.
* @throws UnifyException
* if container is not started.
*/
public List getComponentNames(Class extends UnifyComponent> componentType) throws UnifyException {
// checkStarted();
List names = new ArrayList();
for (InternalUnifyComponentInfo iuc : internalUnifyComponentInfos.values()) {
if (componentType.isAssignableFrom(iuc.getType())) {
names.add(iuc.getName());
}
}
return names;
}
/**
* Gets component configuration by name.
*
* @param name
* the component name
* @return the component configuration if found, otherwise null.
* @throws UnifyException
* if container is not started. If an error occurs
*/
public UnifyComponentConfig getComponentConfig(String name) throws UnifyException {
checkStarted();
InternalUnifyComponentInfo iuci = getInternalUnifyComponentInfo(name);
if (iuci != null) {
return iuci.getUnifyComponentConfig();
}
return null;
}
/**
* Gets all component configurations with types that extend or implement
* specific component type.
*
* @param componentType
* the component types to match
* @return a list of component configurations that match with supplied type.
* @throws UnifyException
* if container is not started.
*/
public List getComponentConfigs(Class extends UnifyComponent> componentType)
throws UnifyException {
checkStarted();
List configList = new ArrayList();
for (InternalUnifyComponentInfo iuc : internalUnifyComponentInfos.values()) {
if (componentType.isAssignableFrom(iuc.getType())) {
configList.add(iuc.getUnifyComponentConfig());
}
}
return configList;
}
/**
* Gets a UPL component with specified descriptor.
*
* @param locale
* the locale
* @param descriptor
* the UPL descriptor
* @param cached
* the cached flag.
* @return If the cached flag is set, the container returns a cached instance
* with the same descriptor and locale if found. Otherwise, a new
* instance is returned.
* @throws UnifyException
* if an error occurs
*/
public UplComponent getUplComponent(Locale locale, String descriptor, boolean cached) throws UnifyException {
if (cached) {
return cachedLocaleUplComponentMap.get(locale, descriptor);
}
try {
UplElementAttributes uplElementAttributes = uplCompiler.compileDescriptor(locale, descriptor);
UplComponent uplComponent =
(UplComponent) getComponent(uplElementAttributes.getComponentName(), null, uplElementAttributes);
return uplComponent;
} finally {
initializationTrailThreadLocal.remove();
}
}
/**
* Gets a UPL component using supplied attributes key.
*
* @param locale
* the component locale
* @param attributesKey
* the UPL element attributes key
* @return the UPL component
* @throws UnifyException
* if container is not started. If component with name is unknown.
* If component instantiation error occurs.
*/
public UplComponent getUplComponent(Locale locale, String attributesKey) throws UnifyException {
try {
UplElementAttributes uplElementAttributes = uplCompiler.getUplElementAttributes(locale, attributesKey);
UplComponent uplComponent =
(UplComponent) getComponent(uplElementAttributes.getComponentName(), null, uplElementAttributes);
return uplComponent;
} finally {
initializationTrailThreadLocal.remove();
}
}
/**
* Returns classes of a particular type annotated with a specific type of
* annotation.
*
* @param classType
* the annotated class type
* @param annotationClass
* the annotation
* @param packages
* packages to restrict search to. This parameter is optional.
* @return list of annotated classes
* @throws UnifyException
* if an error occurs
*/
public List> getAnnotatedClasses(Class classType,
Class extends Annotation> annotationClass, String... packages) throws UnifyException {
return unifyContainerEnvironment.getTypeRepository().getAnnotatedClasses(classType, annotationClass, packages);
}
/**
* Returns classes of a particular type annotated with a specific type of
* annotation.
*
* @param classType
* the annotated class type
* @param annotationClass
* the annotation
* @param excludedPackages
* packages to exclude search from. This parameter is optional.
* @return list of annotated classes
* @throws UnifyException
* if an error occurs
*/
public List> getAnnotatedClassesExcluded(Class classType,
Class extends Annotation> annotationClass, String... excludedPackages) throws UnifyException {
return unifyContainerEnvironment.getTypeRepository().getAnnotatedClassesExcluded(classType, annotationClass,
excludedPackages);
}
public String getNodeId() {
return nodeId;
}
public String getInstanceCode() {
return (String) unifySettings.get(UnifyCorePropertyConstants.APPLICATION_CODE);
}
public String getInstanceName() {
return (String) unifySettings.get(UnifyCorePropertyConstants.APPLICATION_NAME);
}
public String getDeploymentVersion() {
return deploymentVersion;
}
public List getStaticSettings() {
return staticSettings;
}
public Object getSetting(String name) {
return unifySettings.get(name);
}
public String getWorkingPath() {
return unifyContainerEnvironment.getWorkingPath();
}
public boolean isClusterMode() {
return clusterMode;
}
public boolean isProductionMode() {
return productionMode;
}
public boolean isDeploymentMode() {
return deploymentMode;
}
public RequestContextManager getRequestContextManager() {
return requestContextManager;
}
public ResourceBundles getMessages() {
return messages;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* Gets a component by name. If a component is configured as a singleton, this
* method would always return the same instance for specified name, otherwise a
* new component instance is always created.
*
* @param name
* the component name
* @return the component
* @throws UnifyException
* if container is not started. If component with name is unknown.
* If component instantiation error occurs.
*/
public UnifyComponent getComponent(String name) throws UnifyException {
return getComponent(name, null, null);
}
/**
* Gets a component by name using alternate settings. Applies to non-singletons
* only..
*
* @param name
* the component name
* @param altSettings
* the alternate settings
* @return the component
* @throws UnifyException
* if container is not started. If component with name is unknown.
* If component is a singleton. If component instantiation error
* occurs.
*/
public UnifyComponent getComponent(String name, Setting... altSettings) throws UnifyException {
return getComponent(name, new UnifyComponentSettings(altSettings), null);
}
/**
* Gets a component by name using alternate settings. Applies to non-singletons
* only..
*
* @param name
* the component name
* @param altSettings
* the alternate settings
* @return the component
* @throws UnifyException
* if container is not started. If component with name is unknown.
* If component is a singleton. If component instantiation error
* occurs.
*/
public UnifyComponent getComponent(String name, UnifyComponentSettings altSettings) throws UnifyException {
return getComponent(name, altSettings, null);
}
/**
* Checks if component with name is defined in container.
*
* @param name
* the component name
* @return a true value if component with name exists otherwise false
* @throws UnifyException
* If component an error occurs.
*/
public boolean isComponent(String name) throws UnifyException {
return internalResolutionMap.containsKey(name) || internalUnifyComponentInfos.containsKey(name)
|| aliases.containsKey(name);
}
/**
* Begins a synchronization block with specified lock. Blocks until
* synchronization handle is obtained or an error occurs. Lock should be
* released by calling {@link #endClusterLock(String)}.
*
* @param lockName
* the lock name
* @throws UnifyException
* if an error occurs
*/
public void beginClusterLock(String lockName) throws UnifyException {
clusterService.beginSynchronization(lockName);
}
/**
* Ends a synchronisation block for specified lock.
*
* @param lockName
* the lock name
* @throws UnifyException
* if an error occurs
*/
public void endClusterLock(String lockName) throws UnifyException {
clusterService.endSynchronization(lockName);
}
/**
* Tries to grab the cluster master synchronization lock.
*
* @return a true value is lock is obtained otherwise false
* @throws UnifyException
* if an error occurs
*/
public boolean grabClusterMasterLock() throws UnifyException {
return clusterService.grabMasterSynchronizationLock();
}
/**
* Tries to grab a cluster synchronization lock. Lock must be released after use
* with {@link #releaseClusterLock(String)}
*
* @param lockName
* the lock name
* @return a true value is lock is obtained otherwise false
* @throws UnifyException
* if an error occurs
*/
public boolean grabClusterLock(String lockName) throws UnifyException {
return clusterService.grabSynchronizationLock(lockName);
}
/**
* Checks if current node has a hold on a cluster synchronization lock.
*
* @param lockName
* the lock name
* @return a true value is lock is held otherwise false
* @throws UnifyException
* if an error occurs
*/
public boolean isWithClusterLock(String lockName) throws UnifyException {
return clusterService.isWithSynchronizationLock(lockName);
}
/**
* Releases a cluster synchronization lock.
*
* @param lockName
* the lock name
* @return a true value if lock was released
* @throws UnifyException
* if an error occurs
*/
public boolean releaseClusterLock(String lockName) throws UnifyException {
return clusterService.releaseSynchronizationLock(lockName);
}
/**
* Broadcasts a cluster command to other nodes.
*
* @param command
* the command to broadcast
* @param params
* the command parameters
* @throws UnifyException
* if an error occurs
*/
public void broadcastToOtherNodes(String command, String... params) throws UnifyException {
clusterService.broadcastToOtherNodes(command, params);
}
/**
* Broadcasts attribute to all sessions in this node.
*
* @param name
* the attribute name
* @param value
* the attribute value. A null value clears attribute.
* @throws UnifyException
* if an error occurs
*/
public void broadcastToSessions(String name, Object value) throws UnifyException {
userSessionManager.broadcast(name, value);
}
/**
* Broadcasts attribute to specific application session context in this node.
*
* @param sessionId
* the session ID
* @param name
* the attribute name
* @param value
* the attribute value. A null value clears attribute.
* @throws UnifyException
* if an error occurs
*/
public void broadcastToSession(String sessionId, String name, Object value) throws UnifyException {
userSessionManager.broadcast(sessionId, name, value);
}
private UnifyComponent getComponent(String name, UnifyComponentSettings altSettings,
UplElementAttributes uplElementAttributes) throws UnifyException {
checkStarted();
UnifyComponent unifyComponent = null;
try {
UnifyComponentConfig unifyComponentConfig = null;
InternalUnifyComponentInfo iuci = getInternalUnifyComponentInfo(name);
if (iuci != null) {
unifyComponentConfig = iuci.getUnifyComponentConfig();
}
if (unifyComponentConfig == null) {
// If supplied name is alias, get actual name and fetch configuration
String actualName = aliases.get(name);
if (actualName != null) {
iuci = getInternalUnifyComponentInfo(actualName);
if (iuci != null) {
unifyComponentConfig = iuci.getUnifyComponentConfig();
}
}
}
if (unifyComponentConfig == null) {
throw new UnifyException(UnifyCoreErrorConstants.COMPONENT_UNKNOWN_COMP, name);
}
if (unifyComponentConfig.isSingleton()) {
if (altSettings != null) {
throw new UnifyException(UnifyCoreErrorConstants.COMPONENT_ALTSETTINGS_SINGLETON, name);
}
unifyComponent = singletonComponentMap.get(unifyComponentConfig.getName(), unifyComponentConfig,
uplElementAttributes);
} else {
if (altSettings != null) {
// Validate alternate settings
UnifyComponentSettings settings = unifyComponentConfig.getSettings();
for (String property : altSettings.getPropertyNames()) {
if (!settings.isProperty(property)) {
throw new UnifyException(UnifyCoreErrorConstants.COMPONENT_ALTSETTINGS_UNKNOWN_PROPERTY,
name, property);
}
}
}
// Create instance
unifyComponent = unifyComponentConfig.getType().newInstance();
initializeComponent(unifyComponentConfig, altSettings, unifyComponent, uplElementAttributes);
}
} catch (UnifyException e) {
throw e;
} catch (Exception e) {
throw new UnifyException(e, UnifyCoreErrorConstants.COMPONENT_INSTANTIATION_ERROR, name);
} finally {
initializationTrailThreadLocal.remove();
}
return unifyComponent;
}
private void initializeComponent(UnifyComponentConfig unifyComponentConfig, UnifyComponentSettings altSettings,
UnifyComponent unifyComponent, UplElementAttributes uplElementAttributes) throws UnifyException {
InitializationTrail initializationTrail = initializationTrailThreadLocal.get();
initializationTrail.joinTrail(unifyComponentConfig.getName());
boolean success = false;
try {
// Get component context
UnifyComponentContext unifyComponentContext = componentContextMap.get(unifyComponentConfig.getName());
// Fetch and set (inject) fields
Class> clazz = unifyComponentConfig.getType();
UnifyComponentSettings settings = unifyComponentConfig.getSettings();
for (String property : settings.getPropertyNames()) {
Object value = null;
if (altSettings != null) {
value = altSettings.getSettingValue(property);
}
if (value == null) {
value = settings.getSettingValue(property);
}
Field field = ReflectUtils.getField(clazz, property);
if (value == null && settings.isAutoInject(property)) {
if (UnifyComponent.class.isAssignableFrom(field.getType())) {
List names = namelessConfigurableSuggestions.get(field.getType());
if (names.size() == 1) { // Check perfect suggestion
value = names.get(0);
} else if(names.size() > 1) {
// TODO throw exception to many possible types to inject
}
}
}
if (value != null) {
String[] configValues = resolveConfigValue(value);
injectFieldValue(unifyComponent, field, configValues);
}
}
// Set UPL attributes if necessary
if (uplElementAttributes != null) {
((UplComponent) unifyComponent).setUplAttributes(uplElementAttributes);
}
// Initialize
unifyComponent.initialize(unifyComponentContext);
success = true;
} catch (UnifyException e) {
throw e;
} catch (Exception e) {
throw new UnifyException(e, UnifyCoreErrorConstants.COMPONENT_INITIALIZATION_ERROR,
unifyComponentConfig.getName());
} finally {
initializationTrail.leaveTrail();
InternalUnifyComponentInfo iuci = this.getInternalUnifyComponentInfo(unifyComponentConfig.getName());
Date now = new Date();
if (success) {
if (iuci.getFirstPassTime() == null) {
iuci.setFirstPassTime(now);
}
iuci.setLastPassTime(now);
iuci.incrementPassCount();
} else {
if (iuci.getFirstFailTime() == null) {
iuci.setFirstFailTime(now);
}
iuci.setLastFailTime(now);
iuci.incrementFailCount();
}
}
}
/**
* Injects value into component field, performing necessary conversion
*
* @param unifyComponent
* - the component
* @param field
* - the field to set
* @param configValues
* - the value to inject
*/
@SuppressWarnings("unchecked")
private void injectFieldValue(UnifyComponent unifyComponent, Field field, String[] configValues)
throws UnifyException {
ReflectUtils.assertNonStaticNonFinal(field);
try {
Object valueToInject = null;
Class> fieldClass = field.getType();
if (fieldClass.isArray()) {
Class> arrFieldClass = fieldClass.getComponentType();
if (UnifyComponent.class.isAssignableFrom(arrFieldClass)) {
Object[] tempArray = getComponents(arrFieldClass, configValues).values().toArray();
valueToInject = Array.newInstance(arrFieldClass, tempArray.length);
for (int i = 0; i < tempArray.length; i++) {
Array.set(valueToInject, i, tempArray[i]);
}
}
} else if (Collection.class.isAssignableFrom(fieldClass)) {
Class> colFieldClass = ReflectUtils.getArgumentType(field.getGenericType(), 0);
if (UnifyComponent.class.isAssignableFrom(colFieldClass)) {
Collection