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.impl; 018 019import java.io.IOException; 020import java.net.URISyntaxException; 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027import java.util.SortedMap; 028 029import org.apache.camel.Component; 030import org.apache.camel.ComponentConfiguration; 031import org.apache.camel.Endpoint; 032import org.apache.camel.spi.EndpointCompleter; 033import org.apache.camel.util.ObjectHelper; 034import org.apache.camel.util.URISupport; 035import org.apache.camel.util.UnsafeUriCharactersEncoder; 036 037/** 038 * Useful base class for implementations of {@link ComponentConfiguration} 039 */ 040public abstract class ComponentConfigurationSupport implements ComponentConfiguration { 041 protected final Component component; 042 private Map<String, Object> propertyValues = new HashMap<String, Object>(); 043 private String baseUri; 044 045 public ComponentConfigurationSupport(Component component) { 046 this.component = component; 047 } 048 049 @Override 050 public Map<String, Object> getParameters() { 051 return Collections.unmodifiableMap(propertyValues); 052 } 053 054 @Override 055 public void setParameters(Map<String, Object> newValues) { 056 ObjectHelper.notNull(newValues, "propertyValues"); 057 this.propertyValues.clear(); 058 // lets validate each property as we set it 059 Set<Map.Entry<String, Object>> entries = newValues.entrySet(); 060 for (Map.Entry<String, Object> entry : entries) { 061 setParameter(entry.getKey(), entry.getValue()); 062 } 063 } 064 065 @Override 066 public Object getParameter(String name) { 067 validatePropertyName(name); 068 return propertyValues.get(name); 069 } 070 071 @Override 072 public void setParameter(String name, Object value) { 073 Object convertedValue = validatePropertyValue(name, value); 074 propertyValues.put(name, convertedValue); 075 } 076 077 /** 078 * Returns the base URI without any scheme or URI query parameters (property values) 079 */ 080 @Override 081 public String getBaseUri() { 082 return baseUri; 083 } 084 085 @Override 086 public void setBaseUri(String baseUri) { 087 this.baseUri = baseUri; 088 } 089 090 @Override 091 public Endpoint createEndpoint() throws Exception { 092 String uri = getUriString(); 093 return component.createEndpoint(uri); 094 } 095 096 /** 097 * Configures the properties on the given endpoint 098 */ 099 @Override 100 public void configureEndpoint(Endpoint endpoint) { 101 Map<String, Object> map = getParameters(); 102 if (map != null) { 103 Set<Map.Entry<String, Object>> entries = map.entrySet(); 104 for (Map.Entry<String, Object> entry : entries) { 105 setEndpointParameter(endpoint, entry.getKey(), entry.getValue()); 106 } 107 } 108 // TODO validate all the values are valid (e.g. mandatory) 109 } 110 111 @Override 112 public String getUriString() { 113 List<String> queryParams = new ArrayList<String>(); 114 for (Map.Entry<String, Object> entry : getParameters().entrySet()) { 115 String key = entry.getKey(); 116 Object value = entry.getValue(); 117 // convert to "param=value" format here, order will be preserved 118 if (value instanceof List) { 119 for (Object item : (List<?>)value) { 120 queryParams.add(key + "=" + UnsafeUriCharactersEncoder.encode(item.toString())); 121 } 122 } else { 123 queryParams.add(key + "=" + UnsafeUriCharactersEncoder.encode(value.toString())); 124 } 125 } 126 Collections.sort(queryParams); 127 StringBuilder builder = new StringBuilder(); 128 String base = getBaseUri(); 129 if (base != null) { 130 builder.append(base); 131 } 132 String separator = "?"; 133 for (String entry : queryParams) { 134 builder.append(separator); 135 builder.append(entry); 136 separator = "&"; 137 } 138 return builder.toString(); 139 } 140 141 @Override 142 public void setUriString(String uri) throws URISyntaxException { 143 String path = uri; 144 int idx = path.indexOf('?'); 145 Map<String, Object> newParameters = Collections.emptyMap(); 146 if (idx >= 0) { 147 path = path.substring(0, idx); 148 String query = uri.substring(idx + 1); 149 newParameters = URISupport.parseQuery(query, true); 150 } 151 setBaseUri(path); 152 setParameters(newParameters); 153 } 154 155 @Override 156 public ParameterConfiguration getParameterConfiguration(String name) { 157 return getParameterConfigurationMap().get(name); 158 } 159 160 public List<String> completeEndpointPath(String completionText) { 161 if (component instanceof EndpointCompleter) { 162 EndpointCompleter completer = (EndpointCompleter) component; 163 return completer.completeEndpointPath(this, completionText); 164 } 165 return new ArrayList<String>(); 166 } 167 168 public String createParameterJsonSchema() { 169 // favor loading the json schema from the built-time generated file 170 String defaultName = component.getCamelContext().resolveComponentDefaultName(component.getClass().getName()); 171 if (defaultName != null) { 172 try { 173 return component.getCamelContext().getComponentParameterJsonSchema(defaultName); 174 } catch (IOException e) { 175 // ignore as we fallback to create the json at runtime 176 } 177 } 178 179 // fallback to resolving at runtime 180 SortedMap<String, ParameterConfiguration> map = getParameterConfigurationMap(); 181 StringBuilder buffer = new StringBuilder("{\n \"properties\": {"); 182 boolean first = true; 183 for (Map.Entry<String, ParameterConfiguration> entry : map.entrySet()) { 184 if (first) { 185 first = false; 186 } else { 187 buffer.append(","); 188 } 189 buffer.append("\n "); 190 buffer.append(entry.getValue().toJson()); 191 } 192 buffer.append("\n }\n}\n"); 193 return buffer.toString(); 194 } 195 196 /** 197 * Allow implementations to validate whether a property name is valid 198 * and either throw an exception or log a warning of an unknown property being used 199 */ 200 protected void validatePropertyName(String name) { 201 } 202 203 /** 204 * Allow implementations to validate whether a property name is valid 205 * and either throw an exception or log a warning of an unknown property being used 206 * and to convert the given value to the correct type before updating the value. 207 */ 208 protected Object validatePropertyValue(String name, Object value) { 209 validatePropertyName(name); 210 return value; 211 } 212 213}