/******************************************************************************* * Copyright (c) 1997, 2008 by ProSyst Software GmbH * http://www.prosyst.com * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * ProSyst Software GmbH - initial API and implementation *******************************************************************************/ package org.eclipse.equinox.internal.io.impl; import java.io.*; import javax.microedition.io.*; import org.eclipse.equinox.internal.util.ref.Log; import org.osgi.framework.*; import org.osgi.service.io.ConnectionFactory; import org.osgi.service.io.ConnectorService; /** * ConnectorService implementation. * * @author Pavlin Dobrev * @version 1.0 */ public class ConnectorServiceImpl implements ConnectorService { static BundleContext bc; ServiceRegistration reg; ConnectionFactoryListener listener; static boolean enableNotification = Activator.getBoolean("eclipse.io.enable.notification"); public static boolean hasDebug; private static Log log; public ConnectorServiceImpl(BundleContext bc, Log log) { ConnectorServiceImpl.log = log; ConnectorServiceImpl.hasDebug = log.getDebug(); init(bc); } public static void debug(int id, String message, Throwable t) { log.debug(0x1200, id, message, t, false); } public ConnectorServiceImpl(BundleContext bc) { init(bc); } private void init(BundleContext bc) { ConnectorServiceImpl.bc = bc; if (enableNotification) { listener = new ConnectionFactoryListener(bc); } reg = bc.registerService(ConnectorService.class.getName(), this, null); } public void close() { reg.unregister(); if (listener != null) { listener.close(); } } public Connection open(String uri) throws IOException { return open(uri, READ_WRITE); } public Connection open(String uri, int mode) throws IOException { return open(uri, mode, false); } static char[] chars = {'~', '='}; public Connection open(String uri, int mode, boolean timeouts) throws IOException { long timeStart = 0; if (hasDebug) { debug(16001, uri + ", " + (mode == READ_WRITE ? "READ_WRITE" : (mode == READ) ? "READ" : "WRITE"), null); timeStart = System.currentTimeMillis(); } try { if (uri == null) { throw new IllegalArgumentException("URL cannot be NULL!"); } int sPos = uri.indexOf(":"); if (sPos < 1) { // scheme must be at least with 1 symbol throw new IllegalArgumentException("Does not have scheme"); } String scheme = uri.substring(0, sPos); StringBuffer filter = new StringBuffer(scheme.length() + 13); filter.append('('); filter.append(ConnectionFactory.IO_SCHEME); filter.append(chars); filter.append(scheme); filter.append(')'); int count = 0; if (listener != null) count = ConnectionFactoryListener.count; Connection c = getConnection(filter.toString(), uri, mode, timeouts, true); if (c == null && listener != null) c = ConnectionFactoryListener.getConnectionNotifier(scheme, uri, mode, timeouts, filter.toString(), count); if (c == null) throw new ConnectionNotFoundException("Failed to create connection " + uri); return c; } finally { if (hasDebug) { debug(16002, String.valueOf(System.currentTimeMillis() - timeStart), null); } } } static protected Connection getConnection(String filter, String uri, int mode, boolean timeouts, boolean connector) throws IOException { ServiceReference[] cfRefs = null; Connection ret = null; try { cfRefs = bc.getServiceReferences(ConnectionFactory.class.getName(), filter); } catch (InvalidSyntaxException ex) { } if (cfRefs != null) { sort(cfRefs, 0, cfRefs.length); } IOException ioExc = null; boolean not_found = false; if (cfRefs != null) for (int i = 0; i < cfRefs.length; i++) { ConnectionFactory prov = (ConnectionFactory) bc.getService(cfRefs[i]); if (prov != null) try { not_found = true; ret = prov.createConnection(uri, mode, timeouts); } catch (IOException e) { if (hasDebug) { debug(16003, prov.getClass().getName(), e); } if (ioExc == null) ioExc = e; } finally { if (ret == null) bc.ungetService(cfRefs[i]); else { if (hasDebug) { debug(16004, prov.getClass().getName(), null); } return ret; } } } if (connector) try { ret = Connector.open(uri, mode, timeouts); } catch (ConnectionNotFoundException ignore) { // returns null -> // ConnectionNotifier // is created debug(16014, null, ignore); } finally { if (ret == null) { if (ioExc != null) throw ioExc; if (not_found) throw new ConnectionNotFoundException("Failed to create connection " + uri); } else { if (hasDebug) { debug(16005, null, null); } } } return ret; } private static void sort(ServiceReference[] array, int start, int end) { int middle = (start + end) / 2; if (start + 1 < middle) sort(array, start, middle); if (middle + 1 < end) sort(array, middle, end); if (start + 1 >= end) return; // this case can only happen when this method is called by // the user if (getRanking(array[middle - 1]) == getRanking(array[middle])) { if (getServiceID(array[middle - 1]) < getServiceID(array[middle])) { return; } } else if (getRanking(array[middle - 1]) >= getRanking(array[middle])) { return; } if (start + 2 == end) { ServiceReference temp = array[start]; array[start] = array[middle]; array[middle] = temp; return; } int i1 = start, i2 = middle, i3 = 0; Object[] merge = new Object[end - start]; while (i1 < middle && i2 < end) { if (getRanking(array[i1]) == getRanking(array[i2])) { merge[i3++] = getServiceID(array[i1]) < getServiceID(array[i2]) ? array[i1++] : array[i2++]; } else { merge[i3++] = getRanking(array[i1]) >= getRanking(array[i2]) ? array[i1++] : array[i2++]; } } if (i1 < middle) System.arraycopy(array, i1, merge, i3, middle - i1); System.arraycopy(merge, 0, array, start, i2 - start); } private static int getRanking(ServiceReference ref) { Object rank = ref.getProperty(Constants.SERVICE_RANKING); if (rank == null || !(rank instanceof Integer)) { return 0; } return ((Integer) rank).intValue(); } private static long getServiceID(ServiceReference ref) { Object sid = ref.getProperty(Constants.SERVICE_ID); if (sid == null || !(sid instanceof Long)) { return 0; } return ((Long) sid).intValue(); } /** * Create and open an <tt>DataInputStream</tt> object for the specified * name. * * @param name * the URI for the connection. * @throws IOException * if and I/O error occurs * @throws ConnectionNotFoundException * if the <tt>Connection</tt> object can not be made or if no * handler for the requested scheme can be found. * @throws IllegalArgumentException * if the given uri is invalid * @return A <tt>DataInputStream</tt> to the given URI */ public DataInputStream openDataInputStream(String name) throws IOException { long timeBegin = 0; if (hasDebug) { debug(16006, name, null); timeBegin = System.currentTimeMillis(); } try { Connection conn = open(name, READ); if (!(conn instanceof InputConnection)) { try { conn.close(); } catch (IOException e) { } throw new IOException("Connection does not implement InputConnection:" + conn.getClass()); } return ((InputConnection) conn).openDataInputStream(); } finally { if (hasDebug) { debug(16007, String.valueOf(System.currentTimeMillis() - timeBegin), null); } } } /** * Create and open an <tt>DataOutputStream</tt> object for the specified * name. * * @param name * the URI for the connection. * @throws IOException * if and I/O error occurs * @throws ConnectionNotFoundException * if the <tt>Connection</tt> object can not be made or if no * handler for the requested scheme can be found. * @throws IllegalArgumentException * if the given uri is invalid * @return A <tt>DataOutputStream</tt> to the given URI */ public DataOutputStream openDataOutputStream(String name) throws IOException { long timeBegin = 0; if (hasDebug) { debug(16008, name, null); } try { Connection conn = open(name, WRITE); if (!(conn instanceof OutputConnection)) { try { conn.close(); } catch (IOException e) { } throw new IOException("Connection does not implement OutputConnection:" + conn.getClass()); } return ((OutputConnection) conn).openDataOutputStream(); } finally { if (hasDebug) { debug(16009, String.valueOf(System.currentTimeMillis() - timeBegin), null); } } } /** * Create and open an <tt>InputStream</tt> object for the specified name. * * * @param name * the URI for the connection. * @throws IOException * if and I/O error occurs * @throws ConnectionNotFoundException * if the <tt>Connection</tt> object can not be made or if no * handler for the requested scheme can be found. * @throws IllegalArgumentException * if the given uri is invalid * @return A <tt>InputStream</tt> to the given URI */ public InputStream openInputStream(String name) throws IOException { long timeBegin = 0; if (hasDebug) { debug(16010, name, null); timeBegin = System.currentTimeMillis(); } try { Connection conn = open(name, READ); if (!(conn instanceof InputConnection)) { try { conn.close(); } catch (IOException e) { } throw new IOException("Connection does not implement InputConnection:" + conn.getClass()); } return ((InputConnection) conn).openInputStream(); } finally { if (hasDebug) { debug(16011, String.valueOf(System.currentTimeMillis() - timeBegin), null); } } } /** * Create and open an <tt>OutputStream</tt> object for the specified name. * * @param name * the URI for the connection. * @throws IOException * if and I/O error occurs * @throws ConnectionNotFoundException * if the <tt>Connection</tt> object can not be made or if no * handler for the requested scheme can be found. * @throws IllegalArgumentException * if the given uri is invalid * @return A <tt>OutputStream</tt> to the given URI */ public OutputStream openOutputStream(String name) throws IOException { long timeBegin = 0; if (hasDebug) { debug(16012, name, null); timeBegin = System.currentTimeMillis(); } try { Connection conn = open(name, WRITE); if (!(conn instanceof OutputConnection)) { try { conn.close(); } catch (IOException e) { } throw new IOException("Connection does not implement OutputConnection:" + conn.getClass()); } return ((OutputConnection) conn).openOutputStream(); } finally { if (hasDebug) { debug(16013, String.valueOf(System.currentTimeMillis() - timeBegin), null); } } } }