/**
* 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.cxf.transport.http.osgi;
import java.util.Dictionary;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transport.http.HTTPConduitConfigurer;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
/**
* Collects configuration information using a ManagedServiceFactory.
*
* Registers a HTTPConduitConfigurer that can configure conduits based on the above
* configuration data.
*
* When used with felix config admin and fileinstall the configuration
* is expected in files named org.apache.cxf.http.conduits-XYZ.cfg
* that has a list of properties like:
*
* url: Regex url to match the configuration
* order: Integer order in which to apply the regex's when multiple regex's match.
* client.*
* tlsClientParameters.*
* proxyAuthorization.*
* authorization.*
*
* Where each of those is a prefix for the attributes that would be on the elements
* of the http:conduit configuration defined at:
*
* http://cxf.apache.org/schemas/configuration/http-conf.xsd
*
* For example:
* client.ReceiveTimeout: 1000
* authorization.Username: Foo
* tlsClientParameters.keyManagers.keyStore.file: mykeys.jks
* etc....
*
*/
class ConfigAdminHttpConduitConfigurer implements ManagedServiceFactory, HTTPConduitConfigurer {
public static final String FACTORY_PID = "org.apache.cxf.http.conduits";
/**
* Stores the configuration data index by matcher and sorted by order
*/
private static class PidInfo implements Comparable<PidInfo> {
final Dictionary<String, String> props;
final Matcher matcher;
final int order;
PidInfo(Dictionary<String, String> p, Matcher m, int o) {
matcher = m;
props = p;
order = o;
}
public Dictionary<String, String> getProps() {
return props;
}
public Matcher getMatcher() {
return matcher;
}
public int compareTo(PidInfo o) {
if (order < o.order) {
return -1;
} else if (order > o.order) {
return 1;
}
// priorities are equal
if (matcher != null) {
if (o.matcher == null) {
return -1;
}
return matcher.pattern().toString().compareTo(o.matcher.pattern().toString());
}
return 0;
}
}
Map<String, PidInfo> props
= new ConcurrentHashMap<String, PidInfo>(4, 0.75f, 2);
CopyOnWriteArrayList<PidInfo> sorted = new CopyOnWriteArrayList<PidInfo>();
public String getName() {
return FACTORY_PID;
}
@SuppressWarnings("unchecked")
public void updated(String pid, @SuppressWarnings("rawtypes") Dictionary properties)
throws ConfigurationException {
if (pid == null) {
return;
}
deleted(pid);
String url = (String)properties.get("url");
String name = (String)properties.get("name");
Matcher matcher = url == null ? null : Pattern.compile(url).matcher("");
String p = (String)properties.get("order");
int order = 50;
if (p != null) {
order = Integer.parseInt(p);
}
PidInfo info = new PidInfo(properties, matcher, order);
props.put(pid, info);
if (url != null) {
props.put(url, info);
}
if (name != null) {
props.put(name, info);
}
addToSortedInfos(info);
}
private synchronized void addToSortedInfos(PidInfo pi) {
int size = sorted.size();
for (int x = 0; x < size; x++) {
PidInfo p = sorted.get(x);
if (pi.compareTo(p) < 0) {
sorted.add(x, pi);
return;
}
}
sorted.add(pi);
}
private synchronized void removeFromSortedInfos(PidInfo pi) {
sorted.remove(pi);
}
public void deleted(String pid) {
PidInfo info = props.remove(pid);
if (info == null) {
return;
}
removeFromSortedInfos(info);
Dictionary<String, String> d = info.getProps();
if (d != null) {
String url = d.get("url");
String name = d.get("name");
if (url != null) {
props.remove(url);
}
if (name != null) {
props.remove(name);
}
}
}
public void configure(String name, String address, HTTPConduit c) {
PidInfo byName = null;
PidInfo byAddress = null;
if (name != null) {
byName = props.get(name);
}
if (address != null) {
byAddress = props.get(address);
if (byAddress == byName) {
byAddress = null;
}
}
HttpConduitConfigApplier applier = new HttpConduitConfigApplier();
for (PidInfo info : sorted) {
if (info.getMatcher() != null
&& info != byName
&& info != byAddress) {
Matcher m = info.getMatcher();
synchronized (m) {
m.reset(address);
if (m.matches()) {
applier.apply(info.getProps(), c, address);
}
}
}
}
if (byAddress != null) {
applier.apply(byAddress.getProps(), c, address);
}
if (byName != null) {
applier.apply(byName.getProps(), c, address);
}
}
}