001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.blueprint; 018 019import java.lang.reflect.Method; 020import java.util.LinkedHashSet; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024 025import org.apache.aries.blueprint.ext.PropertyPlaceholderExt; 026import org.apache.camel.spi.PropertiesSource; 027import org.apache.camel.support.ObjectHelper; 028import org.apache.camel.support.service.ServiceSupport; 029import org.apache.camel.util.ReflectionHelper; 030import org.osgi.service.blueprint.container.BlueprintContainer; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034/** 035 * Blueprint {@link PropertiesSource} which supports looking up 036 * property placeholders from the Blueprint Property Placeholder Service. 037 */ 038public class BlueprintPropertiesSource extends ServiceSupport implements PropertiesSource { 039 040 private static final Logger LOG = LoggerFactory.getLogger(BlueprintPropertiesSource.class); 041 private final BlueprintContainer container; 042 private final List<String> ids; 043 private final Set<PropertyPlaceholderWrapper> placeholders = new LinkedHashSet<>(); 044 045 public BlueprintPropertiesSource(BlueprintContainer container, List<String> ids) { 046 this.container = container; 047 this.ids = ids; 048 } 049 050 @Override 051 public String getName() { 052 return "BlueprintPropertiesSource" + ids; 053 } 054 055 @Override 056 public String getProperty(String name) { 057 String answer = null; 058 059 for (PropertyPlaceholderWrapper placeholder : placeholders) { 060 boolean isDefault = false; 061 if (placeholders.size() > 1) { 062 // okay we have multiple placeholders and we want to return the answer that 063 // is not the default placeholder if there is multiple keys 064 Map map = placeholder.getDefaultProperties(); 065 isDefault = map != null && map.containsKey(name); 066 LOG.trace("Blueprint property key: {} is part of default properties: {}", name, isDefault); 067 } 068 069 try { 070 String candidate = placeholder.retrieveValue(name); 071 if (candidate != null) { 072 if (answer == null || !isDefault) { 073 LOG.trace("Blueprint candidate property key: {} as value: {}", name, answer); 074 answer = candidate; 075 } 076 } 077 } catch (Exception ex) { 078 // Here we just catch the exception and try to use other candidate 079 } 080 } 081 LOG.debug("Blueprint getProperty: {}={}", name, answer); 082 083 return answer; 084 } 085 086 /** 087 * Adds the given Blueprint property placeholder service with the given id 088 * 089 * @param id id of the Blueprint property placeholder service to add. 090 */ 091 private void addPropertyPlaceholder(String id) { 092 Object component = container.getComponentInstance(id); 093 094 if (component instanceof PropertyPlaceholderExt) { 095 Class<?> clazz = component.getClass(); 096 if (clazz != null) { 097 LOG.debug("Adding Blueprint PropertyPlaceholder: {}", id); 098 Method method = ReflectionHelper.findMethod(clazz, "retrieveValue", String.class); 099 Method defaultMethod = ReflectionHelper.findMethod(clazz, "getDefaultProperties"); 100 if (method != null) { 101 method.setAccessible(true); 102 if (defaultMethod != null) { 103 defaultMethod.setAccessible(true); 104 } 105 placeholders.add(new PropertyPlaceholderWrapper(component, method, defaultMethod)); 106 } else { 107 throw new IllegalStateException("Cannot add blueprint property placeholder: " + id 108 + " as the method retrieveValue is not found"); 109 } 110 } 111 } 112 } 113 114 @Override 115 protected void doInit() throws Exception { 116 for (String id : ids) { 117 addPropertyPlaceholder(id); 118 } 119 } 120 121 @Override 122 protected void doStart() throws Exception { 123 // noop 124 } 125 126 @Override 127 protected void doStop() throws Exception { 128 // noop 129 } 130 131 private class PropertyPlaceholderWrapper { 132 133 private final Object delegate; 134 private final Method method; 135 private final Method defaultMethod; 136 137 PropertyPlaceholderWrapper(Object delegate, Method method, Method defaultMethod) { 138 this.delegate = delegate; 139 this.method = method; 140 this.defaultMethod = defaultMethod; 141 } 142 143 String retrieveValue(String key) { 144 Object v = ObjectHelper.invokeMethod(method, delegate, key); 145 return v == null ? null : v.toString(); 146 } 147 148 Map getDefaultProperties() { 149 if (defaultMethod != null) { 150 return (Map) ObjectHelper.invokeMethod(defaultMethod, delegate); 151 } 152 return null; 153 } 154 } 155 156}