org.apache.cxf.dosgi.dsw.OsgiUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cxf.dosgi.dsw.OsgiUtils.java

Source

/** 
 * 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.dosgi.dsw;

import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.cxf.dosgi.dsw.decorator.ServiceDecorator;
import org.apache.cxf.dosgi.dsw.qos.IntentMap;
import org.apache.cxf.dosgi.dsw.service.RemoteServiceAdminCore;
import org.apache.cxf.ws.policy.spring.PolicyNamespaceHandler;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.service.remoteserviceadmin.EndpointDescription;
import org.springframework.context.ApplicationContext;
import org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext;

public final class OsgiUtils {

    // TODO: cleanup old code fragments !!!

    private static final Logger LOG = Logger.getLogger(OsgiUtils.class.getName());

    private static final String REMOTE_SERVICES_HEADER_NAME = "Remote-Service";
    private static final String REMOTE_SERVICES_DIRECTORY = "OSGI-INF/remote-service";
    private static final String REMOTE_SERVICES_NS = "http://www.osgi.org/xmlns/sd/v1.0.0";

    static final String[] INTENT_MAP = { "/OSGI-INF/cxf/intents/intent-map.xml" };

    private static final String SERVICE_DESCRIPTION_ELEMENT = "service-description";

    //    private static final String PROVIDE_INTERFACE_ELEMENT = "provide";
    //    private static final String PROVIDE_INTERFACE_NAME_ATTRIBUTE = "interface";

    //    private static final String PROPERTY_ELEMENT = "property";
    //    private static final String PROPERTY_NAME_ATTRIBUTE = "name";
    //    private static final String PROPERTY_VALUE_ATTRIBUTE = "value";
    //    private static final String PROPERTY_INTERFACE_ATTRIBUTE = "interface";

    //    private static final String INTERFACE_WILDCARD = "*";
    //    private static final String INTERFACE_SEPARATOR = ":";

    private OsgiUtils() {
    }

    //    // Used by PublishHook
    //    public static ServiceEndpointDescription getRemoteReference(ServiceReference sref, boolean matchAllNames) {
    //
    //        String[] names = (String[])sref.getProperty(org.osgi.framework.Constants.OBJECTCLASS);
    //        if (names == null || names.length == 0) {
    //            return null;
    //        }
    //
    //        Map<String, Object> userProperties = new HashMap<String, Object>();
    //        for (String key : sref.getPropertyKeys()) {
    //            userProperties.put(key, sref.getProperty(key));
    //        }
    //        List<ServiceEndpointDescription> srefs = getRemoteReferences(sref.getBundle(), names, userProperties,
    //                                                                     matchAllNames);
    //        setAdditionalProperties(sref, userProperties);
    //
    //        if (srefs.isEmpty()) {
    //            return new ServiceEndpointDescriptionImpl(Arrays.asList(names), userProperties);
    //        }
    //
    //        return srefs.get(0);
    //    }

    //    @SuppressWarnings("unchecked")
    //    public static List<ServiceEndpointDescription> getRemoteReferences(Bundle b, String[] names,
    //                                                                       Map<String, Object> userProperties,
    //                                                                       boolean matchAllNames) {
    //
    //        List<Element> references = getAllDescriptionElements(b);
    //
    //        List<ServiceEndpointDescription> srefs = new ArrayList<ServiceEndpointDescription>();
    //        Namespace ns = Namespace.getNamespace(REMOTE_SERVICES_NS);
    //        for (Element ref : references) {
    //            List<String> iNames = getProvidedInterfaces(ref.getChildren(PROVIDE_INTERFACE_ELEMENT, ns));
    //            if (!serviceNamesMatch(names, iNames, matchAllNames)) {
    //                continue;
    //            }
    //
    //            Map<String, Object> remoteProps = new HashMap<String, Object>(userProperties);
    //            addProperties(remoteProps, ref.getChildren(PROPERTY_ELEMENT, ns));
    //            srefs.add(new ServiceEndpointDescriptionImpl(iNames, remoteProps));
    //        }
    //        return srefs;
    //
    //    }

    //    public static ServiceEndpointDescription[] flattenServiceDescription(ServiceEndpointDescription sd) {
    //        ServiceEndpointDescription[] list = null;
    //        int interfaceNameCount = sd.getProvidedInterfaces().size();
    //        if (sd.getProvidedInterfaces() == null || interfaceNameCount <= 1) {
    //            list = new ServiceEndpointDescription[] {
    //                sd
    //            };
    //        } else {
    //            String[] iNames = (String[])sd.getProvidedInterfaces().toArray(new String[interfaceNameCount]);
    //            list = new ServiceEndpointDescription[iNames.length];
    //            for (int i = 0; i < iNames.length; i++) {
    //                Map<String, Object> props = excludeProperty(sd.getProperties(),
    //                                                            Constants.EXPORTED_INTERFACES,
    //                                                            Constants.EXPORTED_INTERFACES_OLD,
    //                                                            Constants.RS_PROVIDER_GLOBAL_PROP_KEY,
    //                                                            Constants.RS_PROVIDER_EXPECTED_PROP_KEY,
    //                                                            Constants.RS_PROVIDER_PROP_KEY);
    //
    //                String keys[] = props.keySet().toArray(new String[props.size()]);
    //                for (int j = 0; j < keys.length; j++) {
    //                    int sep = keys[j].indexOf(INTERFACE_SEPARATOR);
    //                    if (sep > -1) {
    //                        String value = (String)props.remove(keys[j]);
    //                        String root = keys[j].substring(0, sep);
    //                        String iface = sep + INTERFACE_SEPARATOR.length() < keys[j].length() ? keys[j]
    //                            .substring(sep + INTERFACE_SEPARATOR.length()) : "";
    //                        if (iNames[i].equals(iface)) {
    //                            props.put(root, value);
    //                        }
    //                    }
    //                }
    //                list[i] = new ServiceEndpointDescriptionImpl(iNames[i], props);
    //            }
    //        }
    //        return list;
    //    }

    //    private static Map<String, Object> excludeProperty(Map properties, String... excludes) {
    //        Collection<String> exList = Arrays.asList(excludes);
    //
    //        Map<String, Object> pruned = new HashMap<String, Object>();
    //        for (Object key : properties.keySet()) {
    //            if (exList.contains(key)) {
    //                // exclude
    //            } else {
    //                pruned.put((String)key, properties.get(key));
    //            }
    //        }
    //        return pruned;
    //    }

    @SuppressWarnings("unchecked")
    public static List<Element> getAllDescriptionElements(Bundle b) {
        Object directory = null;

        Dictionary headers = b.getHeaders();
        if (headers != null) {
            directory = headers.get(REMOTE_SERVICES_HEADER_NAME);
        }

        if (directory == null) {
            directory = REMOTE_SERVICES_DIRECTORY;
        }

        Enumeration urls = b.findEntries(directory.toString(), "*.xml", false);
        if (urls == null) {
            return Collections.emptyList();
        }

        List<Element> elements = new ArrayList<Element>();
        while (urls.hasMoreElements()) {
            URL resourceURL = (URL) urls.nextElement();
            try {
                Document d = new SAXBuilder().build(resourceURL.openStream());
                Namespace ns = Namespace.getNamespace(REMOTE_SERVICES_NS);
                elements.addAll(d.getRootElement().getChildren(SERVICE_DESCRIPTION_ELEMENT, ns));
            } catch (Exception ex) {
                LOG.log(Level.WARNING, "Problem parsing: " + resourceURL, ex);
            }
        }
        return elements;
    }

    //    private static void setAdditionalProperties(ServiceReference sref, Map<String, Object> props) {
    //        BundleContext bc = sref.getBundle().getBundleContext();
    //        ServiceReference[] refs;
    //        try {
    //            refs = bc.getServiceReferences(ServiceDecorator.class.getName(), null);
    //        } catch (InvalidSyntaxException e) {
    //            // should never happen, filter is null
    //            return;
    //        }
    //        if (refs == null) {
    //            return;
    //        }
    //
    //        for (ServiceReference ref : refs) {
    //            Object svc = bc.getService(ref);
    //            if (svc instanceof ServiceDecorator) {
    //                ((ServiceDecorator)svc).decorate(sref, props);
    //            }
    //        }
    //    }

    //    private static boolean serviceNamesMatch(String[] names, List<String> iNames, boolean matchAllNames) {
    //        if (names == null || names.length == 0) {
    //            return false;
    //        }
    //        if (matchAllNames) {
    //            for (String name : names) {
    //                if (!iNames.contains(name)) {
    //                    return false;
    //                }
    //            }
    //            return true;
    //        } else {
    //            for (String name : names) {
    //                if (iNames.contains(name)) {
    //                    return true;
    //                }
    //            }
    //            return false;
    //        }
    //    }

    /*
     * // TODO : consider creating a new List rather than modifyiing the existing one public static void
     * matchServiceDescriptions(List<ServiceEndpointDescription> sds, String interfaceName, Filter filter,
     * boolean matchAll) { for (Iterator<ServiceEndpointDescription> it = sds.iterator(); it.hasNext();) {
     * ServiceEndpointDescription sd = it.next(); if (filter != null && !OsgiUtils.matchAgainstFilter(sd,
     * interfaceName, filter, matchAll)) { it.remove(); } } }
     * @SuppressWarnings("unchecked") public static boolean matchAgainstFilter(ServiceEndpointDescription sd,
     * String interfaceName, Filter filter, boolean matchAll) { Dictionary props = new Hashtable(); for
     * (Object key : sd.getPropertyKeys()) { if (matchAll ||
     * key.toString().startsWith(DistributionConstants.REMOTE)) { props.put(key,
     * sd.getProperty(key.toString())); } } String[] interfaceNames = getProvidedInterfaces(sd,
     * interfaceName); if (interfaceNames != null) { props.put(org.osgi.framework.Constants.OBJECTCLASS,
     * interfaceNames); } return filter.match(props); }
     */

    //    public static String[] getProvidedInterfaces(ServiceEndpointDescription sd, String interfaceName) {
    //
    //        int interfaceNameCount = sd.getProvidedInterfaces().size();
    //        String[] interfaceNames = (String[])sd.getProvidedInterfaces()
    //            .toArray(new String[interfaceNameCount]);
    //        if (interfaceName == null) {
    //            return interfaceNames;
    //        }
    //
    //        for (String s : interfaceNames) {
    //            if (s.equals(interfaceName)) {
    //                return new String[] {
    //                    s
    //                };
    //            }
    //        }
    //        return null;
    //    }

    public static Filter createFilter(BundleContext bc, String filterValue) {

        if (filterValue == null) {
            return null;
        }

        try {
            return bc.createFilter(filterValue);
        } catch (InvalidSyntaxException ex) {
            System.out.println("Invalid filter expression " + filterValue);
        } catch (Exception ex) {
            System.out.println("Problem creating a Filter from " + filterValue);
        }
        return null;
    }

    public static String[] parseIntents(String intentsSequence) {
        return intentsSequence == null ? new String[] {} : intentsSequence.split(" ");
    }

    public static String formatIntents(String[] intents) {
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (String intent : intents) {
            if (first) {
                first = false;
            } else {
                sb.append(' ');
            }
            sb.append(intent);
        }
        return sb.toString();
    }

    //    private static Map<String, Object> getProperties(List<Element> elements) {
    //        Map<String, Object> props = new HashMap<String, Object>();
    //        addProperties(props, elements);
    //        return props;
    //    }

    //    private static void addProperties(Map<String, Object> props, List<Element> elements) {
    //        for (Element p : elements) {
    //            String key = p.getAttributeValue(PROPERTY_NAME_ATTRIBUTE);
    //            String value = p.getAttributeValue(PROPERTY_VALUE_ATTRIBUTE);
    //            if (value == null) {
    //                value = p.getTextTrim();
    //            }
    //
    //            String iface = p.getAttributeValue(PROPERTY_INTERFACE_ATTRIBUTE);
    //            if (key != null) {
    //                props.put(iface == null || iface.length() == 0 ? key : key + INTERFACE_SEPARATOR + iface,
    //                          value);
    //            }
    //        }
    //    }

    //    private static List<String> getProvidedInterfaces(List<Element> elements) {
    //
    //        List<String> names = new ArrayList<String>();
    //
    //        for (Element p : elements) {
    //            String name = p.getAttributeValue(PROVIDE_INTERFACE_NAME_ATTRIBUTE);
    //            if (name != null) {
    //                names.add(name);
    //            }
    //        }
    //
    //        return names;
    //    }

    @SuppressWarnings("unchecked")
    public static <T> OsgiService<T> getOsgiService(BundleContext bc, Class<T> serviceClass) {
        try {
            ServiceReference sr = bc.getServiceReference(serviceClass.getName());
            if (sr != null) {
                Object o = bc.getService(sr);
                if (o != null && serviceClass.isAssignableFrom(o.getClass())) {
                    return new OsgiService(sr, o);
                }
            }
        } catch (Exception ex) {
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("Problem retrieving an OSGI service " + serviceClass.getName() + ", exception : "
                        + ex.getMessage());
            }
        }
        return null;
    }

    public static IntentMap getIntentMap(BundleContext bundleContext) {
        IntentMap im = readIntentMap(bundleContext);
        if (im == null) {
            // Couldn't read an intent map
            LOG.log(Level.FINE, "Using default intent map");
            im = new IntentMap();
            im.setIntents(new HashMap<String, Object>());
        }
        return im;
    }

    static IntentMap readIntentMap(BundleContext bundleContext) {
        List<String> springIntentLocations = new ArrayList<String>();
        for (String mapFile : INTENT_MAP) {
            if (bundleContext.getBundle().getResource(mapFile) == null) {
                LOG.info("Could not find intent map file " + mapFile);
                return null;
            }
            springIntentLocations.add("classpath:" + mapFile);
        }

        try {

            // switch to cxf bundle classloader for spring
            Thread.currentThread().setContextClassLoader(PolicyNamespaceHandler.class.getClassLoader());

            LOG.fine("Loading Intent map from " + springIntentLocations);
            System.out.println("Loading Intent map from " + springIntentLocations);
            OsgiBundleXmlApplicationContext ctx = new OsgiBundleXmlApplicationContext(
                    springIntentLocations.toArray(new String[] {}));
            ctx.setPublishContextAsService(false);
            ctx.setBundleContext(bundleContext);
            ctx.refresh();
            LOG.fine("application context: " + ctx);
            System.out.println("application context: " + ctx);
            IntentMap im = (IntentMap) ctx.getBean("intentMap");
            LOG.fine("retrieved intent map: " + im);
            System.out.println("retrieved intent map: " + im);
            // switch back 
            Thread.currentThread().setContextClassLoader(RemoteServiceAdminCore.class.getClassLoader());

            return im;
        } catch (Throwable t) {
            LOG.log(Level.WARNING, "Intent map load failed: ", t);
            return null;
        }
    }

    // Eg. "(&(" + Constants.OBJECTCLASS + "=Person)(|(sn=Jensen)(cn=Babs J*)))"
    public static Filter createFilterFromProperties(BundleContext bc, Dictionary properties) {

        if (properties == null || properties.isEmpty()) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        sb.append("(&");
        for (Enumeration keys = properties.keys(); keys.hasMoreElements();) {
            String key = keys.nextElement().toString();
            String value = properties.get(key).toString();
            sb.append('(').append(key).append('=').append(value).append(')');
        }
        sb.append(')');
        return createFilter(bc, sb.toString());
    }

    // TODO : move these property helpers into PropertyUtils ?

    public static boolean getBooleanProperty(Map sd, String name) {
        Object value = sd.get(name);
        return toBoolean(value);
    }

    public static boolean toBoolean(Object value) {
        return value instanceof Boolean && ((Boolean) value).booleanValue()
                || value instanceof String && Boolean.parseBoolean((String) value);
    }

    @SuppressWarnings("unchecked")
    public static Collection<String> getMultiValueProperty(Object property) {
        if (property == null) {
            return null;
        }

        if (property instanceof Collection) {
            return (Collection<String>) property;
        } else if (property instanceof String[]) {
            return Arrays.asList((String[]) property);
        } else {
            return Collections.singleton(property.toString());
        }
    }

    public static String getProperty(EndpointDescription sd, String name) {
        Object o = sd.getProperties().get(name);

        if (o != null && o instanceof String) {
            return (String) o;
        }

        return null;

    }

    public static String getProperty(Map dict, String name) {
        Object o = dict.get(name);

        if (o != null && o instanceof String) {
            return (String) o;
        }
        return null;
    }

    //    @SuppressWarnings("unchecked")
    //    public static <T> T getProperty(ServiceEndpointDescription sd, String name, Class<T> type, T defaultValue) {
    //        Object o = sd.getProperty(name);
    //        if (o == null) {
    //            return defaultValue;
    //        }
    //        return type.isAssignableFrom(o.getClass()) ? (T)o : null;
    //    }
    //
    //    public static String[] getPublishableInterfaces(ServiceEndpointDescription sd, ServiceReference sref) {
    //        Collection<String> publishProperty = getMultiValueProperty(sd
    //            .getProperty(Constants.EXPORTED_INTERFACES));
    //        if (publishProperty == null) {
    //            publishProperty = getMultiValueProperty(sd.getProperty(Constants.EXPORTED_INTERFACES_OLD));
    //        }
    //
    //        String[] actualInterfaces = (String[])sref.getProperty(org.osgi.framework.Constants.OBJECTCLASS);
    //        String[] publishableInterfaces = null;
    //
    //        if (actualInterfaces != null && actualInterfaces.length > 0 && publishProperty != null) {
    //
    //            if (publishProperty.size() == 1 && INTERFACE_WILDCARD.equals(publishProperty.iterator().next())) {
    //                // wildcard indicates all interfaces should be published
    //                //
    //                publishableInterfaces = actualInterfaces;
    //            } else {
    //                String[] requestedInterfaces;
    //                if (publishProperty.size() == 0) {
    //                    requestedInterfaces = null;
    //                } else if (publishProperty.size() == 1) {
    //                    requestedInterfaces = tokenize(publishProperty.iterator().next(), ",");
    //                } else {
    //                    requestedInterfaces = publishProperty.toArray(new String[publishProperty.size()]);
    //                }
    //
    //                ArrayList<String> publishableList = new ArrayList<String>();
    //                for (int i = 0; requestedInterfaces != null && i < requestedInterfaces.length; i++) {
    //                    if (contains(actualInterfaces, requestedInterfaces[i])) {
    //                        publishableList.add(requestedInterfaces[i]);
    //                    } else {
    //                        // simply ignore non-exposed interfaces
    //                        //
    //                        LOG.warning("ignoring publish interface, " + requestedInterfaces[i]
    //                                    + ", not exposed by service");
    //                    }
    //                }
    //
    //                if (publishableList.size() > 0) {
    //                    publishableInterfaces = publishableList.toArray(new String[publishableList.size()]);
    //                }
    //            }
    //        }
    //
    //        return publishableInterfaces;
    //    }

    //    private static String[] tokenize(String str, String delim) {
    //        StringTokenizer tokenizer = new StringTokenizer(str, delim);
    //        String[] tokens = new String[tokenizer.countTokens()];
    //        for (int i = 0; tokenizer.hasMoreTokens(); i++) {
    //            tokens[i] = tokenizer.nextToken();
    //        }
    //        return tokens;
    //    }
    //
    //    private static boolean contains(String[] list, String member) {
    //        boolean found = false;
    //        for (int i = 0; i < list.length && !found; i++) {
    //            found = member.equals(list[i]);
    //        }
    //        return found;
    //    }

    /**
     * Tries to retrieve the version of iClass via the PackageAdmin
     * 
     * @param iClass - The interface for which the version should be found
     * @param bc - any valid BundleContext
     * @return the version of the interface or "0.0.0" if no version information could be found or an error
     *         occurred during the retrieval
     */
    public static String getVersion(Class<?> iClass, BundleContext bc) {

        ServiceReference paRef = bc.getServiceReference(PackageAdmin.class.getName());
        if (paRef != null) {
            PackageAdmin pa = (PackageAdmin) bc.getService(paRef);

            Bundle b = pa.getBundle(iClass);
            if (b == null) {
                LOG.info("Unable to find interface version for interface " + iClass.getName()
                        + ". Falling back to 0.0.0");
                return "0.0.0";
            }
            LOG.finest("Interface source bundle: " + b.getSymbolicName());

            ExportedPackage[] ep = pa.getExportedPackages(b);
            LOG.finest("Exported Packages of the source bundle: " + ep);

            String pack = iClass.getPackage().getName();
            LOG.finest("Looking for Package: " + pack);

            for (ExportedPackage p : ep) {
                if (pack.equals(p.getName())) {
                    LOG.fine("found package -> Version: " + p.getVersion());
                    return p.getVersion().toString();
                }
            }
        } else {
            LOG.severe("Was unable to obtain the package admin service -> can't resolve interface versions");
        }

        LOG.info("Unable to find interface version for interface " + iClass.getName() + ". Falling back to 0.0.0");
        return "0.0.0";
    }

    public static String getUUID(BundleContext bc) {
        synchronized ("org.osgi.framework.uuid") {
            String uuid = bc.getProperty("org.osgi.framework.uuid");
            if (uuid == null) {
                uuid = UUID.randomUUID().toString();
                System.setProperty("org.osgi.framework.uuid", uuid);
            }
            return uuid;
        }
    }

}