/* * 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.openejb.assembler.classic.util; import org.apache.openejb.JndiConstants; import org.apache.openejb.OpenEJBException; import org.apache.openejb.OpenEJBRuntimeException; import org.apache.openejb.assembler.classic.Assembler; import org.apache.openejb.assembler.classic.OpenEjbConfiguration; import org.apache.openejb.assembler.classic.ServiceInfo; import org.apache.openejb.loader.SystemInstance; import org.apache.openejb.spi.ContainerSystem; import org.apache.openejb.util.LogCategory; import org.apache.openejb.util.Logger; import org.apache.xbean.recipe.ObjectRecipe; import org.apache.xbean.recipe.Option; import org.apache.xbean.recipe.UnsetPropertiesRecipe; import javax.naming.Context; import javax.naming.NamingException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Properties; // mainly an utility class when using services as config. Null is returned if the action is not possible // (instead of throwing an exception) public final class ServiceInfos { private ServiceInfos() { // no-op } public static Object resolve(final Collection<ServiceInfo> services, final String id) { if (id == null) { return null; } try { return build(services, find(services, id)); } catch (final OpenEJBException e) { throw new OpenEJBRuntimeException(e); } } public static ServiceInfo find(final Collection<ServiceInfo> services, final String id) { for (final ServiceInfo s : services) { if (id.equals(s.id)) { return s; } } return null; } public static ServiceInfo findByClass(final Collection<ServiceInfo> services, final String clazz) { for (final ServiceInfo s : services) { if (clazz.equals(s.className)) { return s; } } return null; } public static List<Object> resolve(final Collection<ServiceInfo> serviceInfos, final String[] ids) { return resolve(serviceInfos, ids, null); } public static List<Object> resolve(final Collection<ServiceInfo> serviceInfos, final String[] ids, final Factory factory) { if (ids == null || ids.length == 0) { return null; } final List<Object> instances = new ArrayList<Object>(); for (final String id : ids) { Object instance = resolve(serviceInfos, id); if (instance == null) { // maybe id == classname try { final Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass(id); if (factory == null) { instance = aClass.newInstance(); } else { instance = factory.newInstance(aClass); } } catch (final Exception e) { // ignore } } if (instance == null) { instance = resolve(SystemInstance.get().getComponent(OpenEjbConfiguration.class).facilities.services, id); } if (instance != null) { instances.add(instance); } } return instances; } public static Properties serviceProperties(final Collection<ServiceInfo> serviceInfos, final String id) { if (id == null) { return null; } final ServiceInfo info = find(serviceInfos, id); if (info == null) { return null; } return info.properties; } private static Object build(final Collection<ServiceInfo> services, final ServiceInfo info) throws OpenEJBException { if (info == null) { return null; } final ObjectRecipe serviceRecipe = Assembler.prepareRecipe(info); return build(services, info, serviceRecipe); } public static Object build(final Collection<ServiceInfo> services, final ServiceInfo info, final ObjectRecipe serviceRecipe) { if ("org.apache.openejb.config.sys.MapFactory".equals(info.className)) { return info.properties; } if (!info.properties.containsKey("properties")) { info.properties.put("properties", new UnsetPropertiesRecipe()); } // we can't ask for having a setter for existing code serviceRecipe.allow(Option.FIELD_INJECTION); serviceRecipe.allow(Option.PRIVATE_PROPERTIES); setProperties(services, info, serviceRecipe); final Object service = serviceRecipe.create(); SystemInstance.get().addObserver(service); // TODO: remove it? in all case the observer should remove itself when done Assembler.logUnusedProperties(serviceRecipe, info); return service; } public static void setProperties(final Collection<ServiceInfo> services, final ServiceInfo info, final ObjectRecipe serviceRecipe) { for (final Map.Entry<Object, Object> entry : info.properties.entrySet()) { // manage links final String key = entry.getKey().toString(); final Object value = entry.getValue(); if (value instanceof String) { String valueStr = value.toString(); if (valueStr.startsWith("collection:")) { // for now only supports Service cause that's where it is useful but feel free to enrich it valueStr = valueStr.substring("collection:".length()); final String[] elt = valueStr.split(" *, *"); final List<Object> val = new ArrayList<>(elt.length); for (final String e : elt) { if (!e.trim().isEmpty()) { val.add(e.startsWith("@") ? lookup(e) : resolve(services, e.startsWith("$") ? e.substring(1) : e)); } } serviceRecipe.setProperty(key, val); } else if (valueStr.startsWith("$")) { serviceRecipe.setProperty(key, resolve(services, valueStr.substring(1))); } else if (valueStr.startsWith("@")) { serviceRecipe.setProperty(key, lookup(value)); } else { serviceRecipe.setProperty(key, value); } } else { serviceRecipe.setProperty(key, entry.getValue()); } } } private static Object lookup(final Object value) { final String name = String.valueOf(value).substring(1); final Context jndiContext = SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext(); Object lookup; try { lookup = jndiContext.lookup(JndiConstants.OPENEJB_RESOURCE_JNDI_PREFIX + name); } catch (final NamingException e) { try { lookup = jndiContext.lookup(name); } catch (final NamingException e1) { Logger.getInstance(LogCategory.OPENEJB, ServiceInfos.class) .warning("Value " + name + " starting with @ but doesn't point to an existing resource, using raw value"); lookup = value; } } return lookup; } public interface Factory { Object newInstance(final Class<?> clazz) throws Exception; } }