/* * 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.karaf.jndi.internal; import org.apache.aries.proxy.ProxyManager; import org.apache.karaf.jndi.JndiService; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import javax.naming.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Implementation of the JNDI Service. */ public class JndiServiceImpl implements JndiService { private BundleContext bundleContext; private ProxyManager proxyManager; private final static String OSGI_JNDI_CONTEXT_PREFIX = "osgi:service"; private final static String OSGI_JNDI_SERVICE_PROPERTY = "osgi.jndi.service.name"; @Override public Map<String, String> names() throws Exception { Map<String, String> result = names("/"); result.putAll(names(OSGI_JNDI_CONTEXT_PREFIX)); return result; } @Override public Map<String, String> names(String name) throws Exception { Map<String, String> map = new HashMap<String, String>(); if (name.startsWith(OSGI_JNDI_CONTEXT_PREFIX)) { // OSGi service binding // make a lookup using directly the OSGi service Bundle[] bundles = bundleContext.getBundles(); for (Bundle bundle : bundles) { ServiceReference<?>[] services = bundle.getRegisteredServices(); if (services != null) { for (ServiceReference service : services) { if (service.getProperty(OSGI_JNDI_SERVICE_PROPERTY) != null) { Object actualService = bundleContext.getService(service); if (proxyManager.isProxy(actualService)) { actualService = proxyManager.unwrap(actualService).call(); } if (service.getProperty(OSGI_JNDI_SERVICE_PROPERTY).toString().startsWith("/")) map.put(OSGI_JNDI_CONTEXT_PREFIX + service.getProperty(OSGI_JNDI_SERVICE_PROPERTY), actualService.getClass().getName()); else map.put(OSGI_JNDI_CONTEXT_PREFIX + "/" + service.getProperty(OSGI_JNDI_SERVICE_PROPERTY), actualService.getClass().getName()); bundleContext.ungetService(service); } } } } } else { // "real" JNDI lookup Context context = new InitialContext(); NamingEnumeration<NameClassPair> pairs = context.list(name); while (pairs.hasMoreElements()) { NameClassPair pair = pairs.nextElement(); Object o; if (name != null) { o = context.lookup(name + "/" + pair.getName()); } else { o = context.lookup(pair.getName()); } if (o instanceof Context) { StringBuilder sb = new StringBuilder(); if (pair.getName().contains(":")) sb.append(pair.getName()); else sb.append("/" + pair.getName()); names((Context) o, sb, map); } else { if (pair.getName().contains(":")) map.put(pair.getName(), pair.getClassName()); else map.put("/" + pair.getName(), pair.getClassName()); } } } return map; } public List<String> contexts() throws Exception { return contexts("/"); } public List<String> contexts(String name) throws Exception { List<String> contexts = new ArrayList<String>(); Context context = new InitialContext(); NamingEnumeration<NameClassPair> pairs = context.list(name); while (pairs.hasMoreElements()) { NameClassPair pair = pairs.nextElement(); Object o; if (name != null) { o = context.lookup(name + "/" + pair.getName()); } else { o = context.lookup(pair.getName()); } if (o instanceof Context) { StringBuilder sb = new StringBuilder(); sb.append("/" + pair.getName()); contexts((Context) o, sb, contexts); } } return contexts; } private void contexts(Context context, StringBuilder sb, List<String> contexts) throws Exception { NamingEnumeration list = context.listBindings(""); while (list.hasMore()) { Binding item = (Binding) list.next(); String name = item.getName(); Object o = item.getObject(); if (o instanceof Context) { if (((Context) o).list("").hasMoreElements()) { sb.append("/").append(name); contexts((Context) o, sb, contexts); } else { contexts.add(sb.toString() + "/" + name); } } } } /** * Recursively list a context/names * * @param ctx the startup context. * @param sb the string builder where to construct the full qualified name. * @param map the final map containing name/class name pairs. * @throws Exception */ private static final void names(Context ctx, StringBuilder sb, Map<String, String> map) throws Exception { NamingEnumeration list = ctx.listBindings(""); while (list.hasMore()) { Binding item = (Binding) list.next(); String className = item.getClassName(); String name = item.getName(); Object o = item.getObject(); if (o instanceof Context) { sb.append("/").append(name); names((Context) o, sb, map); } else { map.put(sb.toString() + "/" + name, className); } } } @Override public void create(String name) throws Exception { Context context = new InitialContext(); String[] splitted = name.split("/"); if (splitted.length > 0) { for (int i = 0; i < splitted.length; i++) { try { Object o = context.lookup(splitted[i]); if (!(o instanceof Context)) { throw new NamingException("Name " + splitted[i] + " already exists"); } } catch (NameNotFoundException e) { context.createSubcontext(splitted[i]); } context = (Context) context.lookup(splitted[i]); } } else { context.createSubcontext(name); } } @Override public void delete(String name) throws Exception { Context context = new InitialContext(); context.destroySubcontext(name); } @Override public void bind(long serviceId, String name) throws Exception { Context context = new InitialContext(); Bundle[] bundles = bundleContext.getBundles(); for (Bundle bundle : bundles) { ServiceReference<?>[] services = bundle.getRegisteredServices(); if (services != null) { for (ServiceReference service : services) { if (service.getProperty(Constants.SERVICE_ID) != null && ((Long) service.getProperty(Constants.SERVICE_ID)) == serviceId) { Object actualService = bundleContext.getService(service); if (proxyManager.isProxy(actualService)) { actualService = proxyManager.unwrap(actualService).call(); } try { String[] splitted = name.split("/"); if (splitted.length > 0) { for (int i = 0; i < splitted.length - 1; i++) { try { Object o = context.lookup(splitted[i]); if (!(o instanceof Context)) { throw new NamingException("Name " + splitted[i] + " already exists"); } } catch (NameNotFoundException nnfe) { context.createSubcontext(splitted[i]); } context = (Context) context.lookup(splitted[i]); } name = splitted[splitted.length - 1]; } context.bind(name, actualService); } finally { bundleContext.ungetService(service); } } } } } } @Override public void alias(String name, String alias) throws Exception { Context context = new InitialContext(); if (name.startsWith(OSGI_JNDI_CONTEXT_PREFIX)) { // get the object Bundle[] bundles = bundleContext.getBundles(); for (Bundle bundle : bundles) { ServiceReference<?>[] services = bundle.getRegisteredServices(); if (services != null) { for (ServiceReference service : services) { if (service.getProperty(OSGI_JNDI_SERVICE_PROPERTY) != null && ((String) service.getProperty(OSGI_JNDI_SERVICE_PROPERTY)).equals(name.substring(OSGI_JNDI_CONTEXT_PREFIX.length() + 1))) { Object actualService = bundleContext.getService(service); try { if (proxyManager.isProxy(actualService)) { actualService = proxyManager.unwrap(actualService).call(); } String[] splitted = alias.split("/"); if (splitted.length > 0) { for (int i = 0; i < splitted.length - 1; i++) { try { Object o = context.lookup(splitted[i]); if (!(o instanceof Context)) { throw new NamingException("Name " + splitted[i] + " already exists"); } } catch (NameNotFoundException nnfe) { context.createSubcontext(splitted[i]); } context = (Context) context.lookup(splitted[i]); } alias = splitted[splitted.length -1]; } context.bind(alias, actualService); } finally { bundleContext.ungetService(service); } } } } } } else { Object object = context.lookup(name); String[] splitted = alias.split("/"); if (splitted.length > 0) { for (int i = 0; i < splitted.length - 1; i++) { try { Object o = context.lookup(splitted[i]); if (!(o instanceof Context)) { throw new NamingException("Name " + splitted[i] + " already exists"); } } catch (NameNotFoundException nnfe) { context.createSubcontext(splitted[i]); } context = (Context) context.lookup(splitted[i]); } alias = splitted[splitted.length - 1]; } context.bind(alias, object); } } @Override public void unbind(String name) throws Exception { InitialContext context = new InitialContext(); if (name.startsWith(OSGI_JNDI_CONTEXT_PREFIX)) { throw new IllegalArgumentException("You can't unbind a name from the " + OSGI_JNDI_CONTEXT_PREFIX + " JNDI context."); } context.unbind(name); } public BundleContext getBundleContext() { return bundleContext; } public void setBundleContext(BundleContext bundleContext) { this.bundleContext = bundleContext; } public ProxyManager getProxyManager() { return proxyManager; } public void setProxyManager(ProxyManager proxyManager) { this.proxyManager = proxyManager; } }