diff options
author | Markus Alexander Kuppe | 2013-11-01 12:34:50 +0000 |
---|---|---|
committer | Markus Alexander Kuppe | 2013-11-06 08:33:26 +0000 |
commit | 573f554d696f8fe5f9fe435ace79e8d2b29bde5c (patch) | |
tree | fbb40ef40c1285de86a9422e9d916f27ef3ac6c5 | |
parent | ac5fa5c492fad225d4708bf29aa18292b4738ebb (diff) | |
download | org.eclipse.ecf-573f554d696f8fe5f9fe435ace79e8d2b29bde5c.tar.gz org.eclipse.ecf-573f554d696f8fe5f9fe435ace79e8d2b29bde5c.tar.xz org.eclipse.ecf-573f554d696f8fe5f9fe435ace79e8d2b29bde5c.zip |
Bug 420858 - [r-OSGi] Sync SF.net and ECF's codebase
https://bugs.eclipse.org/420858
Syncs to SF.net revision "r1317" (2011-02-14 16:41:38 +0100 (Mon, 14 Feb
2011))
16 files changed, 846 insertions, 793 deletions
diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/RemoteOSGiService.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/RemoteOSGiService.java index d38feefdb..4393356ed 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/RemoteOSGiService.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/RemoteOSGiService.java @@ -29,6 +29,7 @@ package ch.ethz.iks.r_osgi; import java.io.IOException; +import java.lang.reflect.Method; import org.osgi.framework.Filter; @@ -254,6 +255,21 @@ public interface RemoteOSGiService { final Object[] args, final AsyncRemoteCallCallback callback); /** + * make an asynchronous remote call to a service + * + * @param service + * the URI of the service + * @param method + * the method to call + * @param args + * the arguments to pass + * @param callback + * a callback to be called when the result is available + */ + void asyncRemoteCall(final URI service, final Method method, + final Object[] args, final AsyncRemoteCallCallback callback); + + /** * get the port on which the corresponding NetworkChannelFactory for the * given protocol listens for incoming connections. * diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ChannelEndpointImpl.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ChannelEndpointImpl.java index 85acd857e..37056fdea 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ChannelEndpointImpl.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ChannelEndpointImpl.java @@ -39,16 +39,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Dictionary; import java.util.HashMap; -import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; -import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.ServiceRegistration; import org.osgi.service.event.Event; @@ -84,7 +80,7 @@ import ch.ethz.iks.r_osgi.streams.InputStreamHandle; import ch.ethz.iks.r_osgi.streams.InputStreamProxy; import ch.ethz.iks.r_osgi.streams.OutputStreamHandle; import ch.ethz.iks.r_osgi.streams.OutputStreamProxy; -import ch.ethz.iks.util.CollectionUtils; +import ch.ethz.iks.r_osgi.types.BoxedPrimitive; /** * <p> @@ -117,6 +113,8 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { int usageCounter = 1; + private static final boolean USE_THREAD_POOL = true; + /** * the channel. */ @@ -184,13 +182,10 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { * filter for events to prevent loops in the remote delivery if the peers * connected by this channel have non-disjoint topic spaces. */ - private static final String NO_LOOPS = "(&(!(" //$NON-NLS-1$ - + RemoteEventMessage.EVENT_SENDER_URI + "=*))" //$NON-NLS-1$ - // [TCK][r-OSGi] NonSerializableException when running remoteserviceadmin ct - // https://bugs.eclipse.org/418740 - + "(!(" + EventConstants.EVENT_TOPIC - + "=org/osgi/service/remoteserviceadmin/*))" //$NON-NLS-1$ - + ")"; //$NON-NLS-1$ + private static final String NO_LOOPS = "(!(" //$NON-NLS-1$ + + RemoteEventMessage.EVENT_SENDER_URI + "=*))"; //$NON-NLS-1$ + + private ThreadGroup threadPool; private ArrayList workQueue = new ArrayList(); @@ -215,11 +210,13 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { ChannelEndpointImpl(final NetworkChannelFactory factory, final URI endpointAddress) throws RemoteOSGiException, IOException { networkChannel = factory.getConnection(this, endpointAddress); - if (RemoteOSGiServiceImpl.DEBUG) { + if (RemoteOSGiServiceImpl.DEBUG && RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log.log(LogService.LOG_DEBUG, "opening new channel " + getRemoteAddress()); //$NON-NLS-1$ } - initThreadPool(); + if (USE_THREAD_POOL) { + initThreadPool(); + } RemoteOSGiServiceImpl.registerChannelEndpoint(this); } @@ -232,7 +229,9 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { ChannelEndpointImpl(final NetworkChannel channel) { networkChannel = channel; channel.bind(this); - initThreadPool(); + if (USE_THREAD_POOL) { + initThreadPool(); + } RemoteOSGiServiceImpl.registerChannelEndpoint(this); } @@ -241,33 +240,35 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { */ private void initThreadPool() { // TODO: tradeoff, could as well be central for all endpoints... - final ThreadGroup threadPool = new ThreadGroup("WorkerThreads" - + toString()); - for (int i = 0; i < RemoteOSGiServiceImpl.MAX_THREADS_PER_ENDPOINT; i++) { - final Thread t = new Thread(threadPool, "r-OSGi ChannelWorkerThread" + i) { - public void run() { - try { - while (!isInterrupted()) { - final Runnable r; - synchronized (workQueue) { - while (workQueue.isEmpty()) { - workQueue.wait(); + // could also be instantiated lazily... + if (USE_THREAD_POOL) { + threadPool = new ThreadGroup("WorkerThreads" + toString()); + for (int i = 0; i < RemoteOSGiServiceImpl.MAX_THREADS_PER_ENDPOINT; i++) { + final Thread t = new Thread(threadPool, "WorkerThread" + i) { + public void run() { + try { + while (!isInterrupted()) { + final Runnable r; + synchronized (workQueue) { + while (workQueue.isEmpty()) { + workQueue.wait(); + } + r = (Runnable) workQueue.remove(0); } - r = (Runnable) workQueue.remove(0); + r.run(); } - r.run(); + } catch (final InterruptedException ie) { + // that's fine } - } catch (InterruptedException ie) { - ie.printStackTrace(); } - } - }; - t.start(); + }; + t.start(); + } } } /** - * process a recieved message. Called by the channel. + * process a received message. Called by the channel. * * @param msg * the received message. @@ -280,35 +281,47 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { return; } final Integer xid = new Integer(msg.getXID()); - final WaitingCallback callback; + final AsyncCallback callback; synchronized (callbacks) { - callback = (WaitingCallback) callbacks.remove(xid); + callback = (AsyncCallback) callbacks.remove(xid); } if (callback != null) { callback.result(msg); return; } else { - final Runnable r = new Runnable() { - public void run() { - final RemoteOSGiMessage reply = handleMessage(msg); - if (reply != null) { - - try { - networkChannel.sendMessage(reply); - } catch (final NotSerializableException nse) { - throw new RemoteOSGiException("Error sending " //$NON-NLS-1$ - + reply, nse); - } catch (NullPointerException npe) { - // channel got closed - } catch (final IOException e) { - dispose(); + if (USE_THREAD_POOL) { + final Runnable r = new Runnable() { + public void run() { + final RemoteOSGiMessage reply = handleMessage(msg); + if (reply != null) { + try { + networkChannel.sendMessage(reply); + } catch (final NotSerializableException nse) { + throw new RemoteOSGiException("Error sending " //$NON-NLS-1$ + + reply, nse); + } catch (final IOException e) { + dispose(); + } } } + }; + synchronized (workQueue) { + workQueue.add(r); + workQueue.notify(); + } + } else { + final RemoteOSGiMessage reply = handleMessage(msg); + if (reply != null) { + + try { + networkChannel.sendMessage(reply); + } catch (final NotSerializableException nse) { + throw new RemoteOSGiException("Error sending " //$NON-NLS-1$ + + reply, nse); + } catch (final IOException e) { + dispose(); + } } - }; - synchronized (workQueue) { - workQueue.add(r); - workQueue.notify(); } } } @@ -438,7 +451,8 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { * @category ChannelEndpoint */ public Dictionary getProperties(final String serviceID) { - return getRemoteReference(serviceID).getProperties(); + final RemoteServiceReferenceImpl rref = getRemoteReference(serviceID); + return rref == null ? null : rref.getProperties(); } /** @@ -451,10 +465,14 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { * @category ChannelEndpoint */ public Dictionary getPresentationProperties(final String serviceID) { + final RemoteServiceReferenceImpl rref = getRemoteReference(serviceID); + final Dictionary attribs = new Hashtable(); attribs.put(RemoteOSGiService.SERVICE_URI, serviceID); - attribs.put(RemoteOSGiService.PRESENTATION, getRemoteReference( - serviceID).getProperty(RemoteOSGiService.PRESENTATION)); + attribs.put( + RemoteOSGiService.PRESENTATION, + rref == null ? null : rref + .getProperty(RemoteOSGiService.PRESENTATION)); return attribs; } @@ -522,7 +540,7 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { return; } - if (RemoteOSGiServiceImpl.DEBUG) { + if (RemoteOSGiServiceImpl.DEBUG && RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log.log(LogService.LOG_DEBUG, "DISPOSING ENDPOINT " + getRemoteAddress()); //$NON-NLS-1$ } @@ -568,6 +586,21 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { } } + // dispose off the thread pool + if (threadPool != null) { + final Thread[] threads = new Thread[RemoteOSGiServiceImpl.MAX_THREADS_PER_ENDPOINT]; + final int count = threadPool.enumerate(threads); + for (int i = 0; i < count; i++) { + threads[i].interrupt(); + try { + threads[i].join(); + } catch (InterruptedException e) { + // + } + } + threadPool.destroy(); + } + remoteServices = null; remoteTopics = null; timeOffset = null; @@ -811,9 +844,11 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { final Bundle bundle = RemoteOSGiActivator.getActivator() .getContext().installBundle(ref.getURI().toString(), in); - retrieveDependencies((String) bundle.getHeaders().get( - Constants.IMPORT_PACKAGE), (String) bundle.getHeaders() - .get(Constants.EXPORT_PACKAGE)); + /* + * retrieveDependencies((String) bundle.getHeaders().get( + * Constants.IMPORT_PACKAGE), (String) bundle.getHeaders() + * .get(Constants.EXPORT_PACKAGE)); + */ if (isProxy) { // store the bundle for state updates and cleanup @@ -858,65 +893,6 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { } /** - * tokenize a package import/export string - * - * @param str - * the string - * @return the tokens - */ - private String[] getTokens(final String str) { - final ArrayList result = new ArrayList(); - final StringTokenizer tokenizer = new StringTokenizer(str, ","); - while (tokenizer.hasMoreTokens()) { - final String token = tokenizer.nextToken(); - final int pos; - // TODO: handle versions for R4! - final String pkg = (pos = token.indexOf(";")) > -1 ? token - .substring(0, pos).trim() : token.trim(); - if (!RemoteOSGiServiceImpl.checkPackageImport(pkg)) { - result.add(pkg); - } - } - - return (String[]) result.toArray(new String[result.size()]); - } - - /** - * get the missing dependencies from remote for a given bundle defined by - * its declared package import and exports. - * - * @param importString - * the declared package imports - * @param exportString - * the declared package exports - */ - private void retrieveDependencies(final String importString, - final String exportString) { - - final Set exports = new HashSet(Arrays.asList(getTokens(exportString))); - final Set imports = new HashSet(Arrays.asList(getTokens(importString))); - - final String[] missing = (String[]) CollectionUtils.rightDifference( - imports, exports).toArray(new String[0]); - - if (missing.length > 0) { - final RequestDependenciesMessage req = new RequestDependenciesMessage(); - req.setPackages(missing); - final DeliverBundlesMessage deps = (DeliverBundlesMessage) sendAndWait(req); - final byte[][] depBytes = deps.getDependencies(); - for (int i = 0; i < depBytes.length; i++) { - try { - RemoteOSGiActivator.getActivator().getContext() - .installBundle("r-osgi://dep/" + missing[i], - new ByteArrayInputStream(depBytes[i])); - } catch (BundleException be) { - be.printStackTrace(); - } - } - } - } - - /** * get the remote reference for a given serviceID. * * @param serviceID @@ -924,6 +900,9 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { * @return the remote service reference, or <code>null</code>. */ RemoteServiceReferenceImpl getRemoteReference(final String uri) { + if (remoteServices == null) { + throw new RemoteOSGiException("Channel is closed."); //$NON-NLS-1$ + } return (RemoteServiceReferenceImpl) remoteServices.get(uri); } @@ -1058,32 +1037,19 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { final String serviceID = suMsg.getServiceID(); final short stateUpdate = suMsg.getType(); - final String serviceURI = getRemoteAddress() - .resolve("#" + serviceID).toString(); - switch (stateUpdate) { case LeaseUpdateMessage.TOPIC_UPDATE: { - // There is an older r-OSGi version that incorrectly sends an ArrayList - // (1.0.0.RC4_v20131016-1848) - Object topicsAdded = suMsg.getPayload()[0]; - if (topicsAdded instanceof List) { - topicsAdded = ((List) topicsAdded).toArray(new String[0]); - } - Object topicsRemoved = suMsg.getPayload()[1]; - if (topicsRemoved instanceof List) { - topicsRemoved = ((List) topicsRemoved).toArray(new String[0]); - } - updateTopics((String[]) topicsAdded, (String[]) topicsRemoved); + updateTopics((String[]) suMsg.getPayload()[0], + (String[]) suMsg.getPayload()[1]); return null; } case LeaseUpdateMessage.SERVICE_ADDED: { - final Dictionary properties = (Dictionary) suMsg.getPayload()[1]; - sanitizeServiceProperties(properties, serviceURI); final RemoteServiceReferenceImpl ref = new RemoteServiceReferenceImpl( (String[]) suMsg.getPayload()[0], serviceID, - properties, this); + (Dictionary) suMsg.getPayload()[1], this); - remoteServices.put(serviceURI, ref); + remoteServices.put(getRemoteAddress().resolve("#" + serviceID) //$NON-NLS-1$ + .toString(), ref); RemoteOSGiServiceImpl .notifyRemoteServiceListeners(new RemoteServiceEvent( @@ -1092,23 +1058,16 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { return null; } case LeaseUpdateMessage.SERVICE_MODIFIED: { - final Dictionary properties = (Dictionary) suMsg.getPayload()[1]; - sanitizeServiceProperties(properties, serviceURI); + final Dictionary newProps = (Dictionary) suMsg.getPayload()[1]; final ServiceRegistration reg = (ServiceRegistration) proxiedServices .get(serviceID); if (reg != null) { - reg.setProperties(properties); + reg.setProperties(newProps); } - final RemoteServiceReferenceImpl ref = getRemoteReference(serviceURI); //$NON-NLS-1$ - // If r-OSGi receives a SERVICE_MODIFIED for service X before it - // knows about X (SERVICE_ADDED), there is no point in updating - // the local service instance. It will fail with an NPE anyway. - // (see https://bugs.eclipse.org/420433) - if (ref == null && reg == null) { - return null; - } - ref.setProperties(properties); + final RemoteServiceReferenceImpl ref = getRemoteReference(getRemoteAddress() + .resolve("#" + serviceID).toString()); //$NON-NLS-1$ + ref.setProperties(newProps); RemoteOSGiServiceImpl .notifyRemoteServiceListeners(new RemoteServiceEvent( RemoteServiceEvent.MODIFIED, ref)); @@ -1119,7 +1078,8 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { return null; } final RemoteServiceReference ref = (RemoteServiceReference) remoteServices - .remove(serviceURI); + .remove(getRemoteAddress().resolve("#" + serviceID) //$NON-NLS-1$ + .toString()); if (ref != null) { RemoteOSGiServiceImpl .notifyRemoteServiceListeners(new RemoteServiceEvent( @@ -1134,7 +1094,12 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { be.printStackTrace(); } proxiedServices.remove(serviceID); - remoteServices.remove(serviceURI); //$NON-NLS-1$ + try { + remoteServices.remove(getRemoteAddress().resolve( + "#" + serviceID).toString()); //$NON-NLS-1$ + } catch (final RemoteOSGiException r) { + // channel was already closed. + } } return null; } @@ -1173,16 +1138,24 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { // invoke method try { - Object result = method.invoke(serv.getServiceObject(), - arguments); + if (!TCPChannelFactory.beSmart) { + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + if (arguments[i] instanceof BoxedPrimitive) { + arguments[i] = ((BoxedPrimitive) arguments[i]) + .getBoxed(); + } + } + } + } + final Object result = method.invoke( + serv.getServiceObject(), arguments); final RemoteCallResultMessage m = new RemoteCallResultMessage(); m.setXID(invMsg.getXID()); if (result instanceof InputStream) { - m - .setResult(getInputStreamPlaceholder((InputStream) result)); + m.setResult(getInputStreamPlaceholder((InputStream) result)); } else if (result instanceof OutputStream) { - m - .setResult(getOutputStreamPlaceholder((OutputStream) result)); + m.setResult(getOutputStreamPlaceholder((OutputStream) result)); } else { m.setResult(result); } @@ -1430,12 +1403,8 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { final RemoteServiceReferenceImpl[] refs = new RemoteServiceReferenceImpl[serviceIDs.length]; for (short i = 0; i < serviceIDs.length; i++) { - final String serviceID = serviceIDs[i]; - final String serviceURI = getRemoteAddress().resolve("#" + serviceID).toString(); - final Dictionary properties = serviceProperties[i]; - sanitizeServiceProperties(properties, serviceURI); refs[i] = new RemoteServiceReferenceImpl(serviceInterfaces[i], - serviceID, properties, this); + serviceIDs[i], serviceProperties[i], this); remoteServices.put(refs[i].getURI().toString(), refs[i]); RemoteOSGiServiceImpl @@ -1446,18 +1415,6 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { return refs; } - private void sanitizeServiceProperties( - final Dictionary properties, final String serviceURI) { - // adjust the properties - properties.put(RemoteOSGiService.SERVICE_URI, serviceURI); - // remove the service PID, if set - properties.remove(Constants.SERVICE_PID); - // remove the R-OSGi registration property - properties.remove(RemoteOSGiService.R_OSGi_REGISTRATION); - // also remote the ECF registration property - properties.remove("org.eclipse.ecf.serviceRegistrationRemote"); //$NON-NLS-1$ - } - /** * perform a stream operation. * @@ -1494,14 +1451,7 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { final String[] topicsRemoved) { if (handlerReg == null) { - // Remote might send a - // ch.ethz.iks.r_osgi.messages.LeaseUpdateMessage.TOPIC_UPDATE - // message - // (see - // ch.ethz.iks.r_osgi.impl.RemoteOSGiServiceImpl.setupTrackers(...).new - // ServiceTrackerCustomizer() {...}.removedService(ServiceReference, - // Object)) with null as the topicsAdded list. Thus, ignore null. - if (topicsAdded != null && topicsAdded.length > 0) { + if (topicsAdded.length > 0) { // register handler final Dictionary properties = new Hashtable(); properties.put(EventConstants.EVENT_TOPIC, topicsAdded); @@ -1537,7 +1487,8 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { } } - if (RemoteOSGiServiceImpl.MSG_DEBUG) { + if (RemoteOSGiServiceImpl.MSG_DEBUG + && RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log.log(LogService.LOG_DEBUG, "NEW REMOTE TOPIC SPACE for " + getRemoteAddress() + " is " //$NON-NLS-1$ //$NON-NLS-2$ + remoteTopics); @@ -1621,9 +1572,12 @@ public final class ChannelEndpointImpl implements ChannelEndpoint { } else if (s[i] instanceof OutputStream) { ((OutputStream) s[i]).close(); } else { - RemoteOSGiServiceImpl.log - .log(LogService.LOG_WARNING, - "Object in input streams map was not an instance of a stream."); //$NON-NLS-1$ + if (RemoteOSGiServiceImpl.DEBUG + && RemoteOSGiServiceImpl.log != null) { + RemoteOSGiServiceImpl.log + .log(LogService.LOG_WARNING, + "Object in input streams map was not an instance of a stream."); //$NON-NLS-1$ + } } } } catch (final IOException e) { diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ChannelEndpointMultiplexer.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ChannelEndpointMultiplexer.java index 5425f5b47..4f6f772b1 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ChannelEndpointMultiplexer.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ChannelEndpointMultiplexer.java @@ -146,7 +146,8 @@ final class ChannelEndpointMultiplexer implements ChannelEndpoint, primary.untrackRegistration(serviceURI); primary = next; primary.trackRegistration(serviceURI, reg); - if (RemoteOSGiServiceImpl.DEBUG) { + if (RemoteOSGiServiceImpl.DEBUG + && RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log.log( LogService.LOG_INFO, "DOING FAILOVER TO " //$NON-NLS-1$ @@ -173,7 +174,8 @@ final class ChannelEndpointMultiplexer implements ChannelEndpoint, primary.untrackRegistration(serviceURI); primary = next; primary.trackRegistration(serviceURI, reg); - if (RemoteOSGiServiceImpl.DEBUG) { + if (RemoteOSGiServiceImpl.DEBUG + && RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log .log( LogService.LOG_INFO, diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/CodeAnalyzer.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/CodeAnalyzer.java index 62dd55431..1519a8f20 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/CodeAnalyzer.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/CodeAnalyzer.java @@ -75,6 +75,11 @@ final class CodeAnalyzer implements ClassVisitor { private final ClassLoader loader; /** + * the class loader of the smart proxy + */ + private ClassLoader smartProxyLoader; + + /** * the closure list. */ private final ArrayList closure = new ArrayList(); @@ -131,7 +136,7 @@ final class CodeAnalyzer implements ClassVisitor { this.loader = loader; if (imports != null) { - final String[] tokens = StringUtils.stringToArray(imports, ","); //$NON-NLS-1$ + final String[] tokens = StringUtils.splitString(imports, ","); //$NON-NLS-1$ importsMap = new HashMap(tokens.length); for (int i = 0; i < tokens.length; i++) { final int pos = tokens[i].indexOf(";"); //$NON-NLS-1$ @@ -147,7 +152,7 @@ final class CodeAnalyzer implements ClassVisitor { } if (exports != null) { - final String[] tokens = StringUtils.stringToArray(exports, ","); //$NON-NLS-1$ + final String[] tokens = StringUtils.splitString(exports, ","); //$NON-NLS-1$ exportsMap = new HashMap(tokens.length); for (int i = 0; i < tokens.length; i++) { final int pos = tokens[i].indexOf(";"); //$NON-NLS-1$ @@ -190,6 +195,14 @@ final class CodeAnalyzer implements ClassVisitor { if (smartProxy != null) { closure.add(smartProxy); + try { + smartProxyLoader = Class.forName(smartProxy).getClassLoader(); + } catch (final ClassNotFoundException c) { + smartProxyLoader = null; + } + if (smartProxyLoader == loader) { + smartProxyLoader = null; + } } if (presentation != null) { closure.add(presentation); @@ -197,7 +210,8 @@ final class CodeAnalyzer implements ClassVisitor { if (explicitInjections != null) { closure.addAll(Arrays.asList(explicitInjections)); } - + + // do the real work while (!closure.isEmpty()) { visit((String) closure.remove(0)); } @@ -292,7 +306,24 @@ final class CodeAnalyzer implements ClassVisitor { } reader.accept(this, ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES); + return; } catch (final IOException ioe) { + if (smartProxyLoader != null) { + try { + final ClassReader reader = new ClassReader( + smartProxyLoader.getResourceAsStream(classFile)); + + injections.put(classFile, reader.b); + if (exportsMap.containsKey(pkg)) { + proxyExports.add(pkg); + } + reader.accept(this, ClassReader.SKIP_DEBUG + + ClassReader.SKIP_FRAMES); + return; + } catch (final IOException ioe2) { + throw new ClassNotFoundException(className); + } + } throw new ClassNotFoundException(className); } } diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ProxyGenerator.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ProxyGenerator.java index a7936092a..b4f2c4c14 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ProxyGenerator.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/ProxyGenerator.java @@ -30,6 +30,8 @@ package ch.ethz.iks.r_osgi.impl; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -56,6 +58,7 @@ import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.osgi.framework.Constants; import org.osgi.service.log.LogService; import ch.ethz.iks.r_osgi.RemoteOSGiService; @@ -219,20 +222,17 @@ class ProxyGenerator implements ClassVisitor, Opcodes { final Attributes attr = mf.getMainAttributes(); attr.putValue("Manifest-Version", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$ attr.putValue("Created-By", "R-OSGi Proxy Generator"); //$NON-NLS-1$ //$NON-NLS-2$ - attr.putValue("Bundle-Activator", className); //$NON-NLS-1$ - attr.putValue("Bundle-Classpath", "."); //$NON-NLS-1$ //$NON-NLS-2$ - attr.putValue("Bundle-SymbolicName", "R-OSGi Proxy Bundle generated for Endpoint " + uri.toString()); //$NON-NLS-1$ //$NON-NLS-2$ - attr - .putValue( - "Import-Package", //$NON-NLS-1$ - "org.osgi.framework, ch.ethz.iks.r_osgi, ch.ethz.iks.r_osgi.types, ch.ethz.iks.r_osgi.channels" //$NON-NLS-1$ - + ("".equals(deliv.getOptionalImports()) ? "" : ", " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - + deliv.getOptionalImports()) - + ("".equals(deliv.getImports()) ? "" : ", ") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - + deliv.getImports()); + attr.putValue(Constants.BUNDLE_ACTIVATOR, className); + attr.putValue(Constants.BUNDLE_CLASSPATH, "."); //$NON-NLS-1$ + attr.putValue( + Constants.IMPORT_PACKAGE, + "org.osgi.framework, ch.ethz.iks.r_osgi, ch.ethz.iks.r_osgi.types, ch.ethz.iks.r_osgi.channels" //$NON-NLS-1$ + + ("".equals(deliv.getImports()) ? "" : ", ") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + deliv.getImports()); if (!"".equals(deliv.getExports())) { //$NON-NLS-1$ - attr.putValue("Export-Package", deliv.getExports()); //$NON-NLS-1$ + attr.putValue(Constants.EXPORT_PACKAGE, deliv.getExports()); } + attr.putValue(Constants.BUNDLE_SYMBOLICNAME, "R-OSGi Proxy Bundle generated for Endpoint " + uri.toString()); //$NON-NLS-1$ //$NON-NLS-2$ final ByteArrayOutputStream bout = new ByteArrayOutputStream(); final JarOutputStream out = new JarOutputStream(bout, mf); @@ -294,12 +294,14 @@ class ProxyGenerator implements ClassVisitor, Opcodes { out.close(); if (RemoteOSGiServiceImpl.PROXY_DEBUG) { - // final File file = - // RemoteOSGiActivator.context.getDataFile(fileName - // + "_" + sourceID + ".jar"); - - // RemoteOSGiServiceImpl.log.log(LogService.LOG_DEBUG, - // "Created Proxy Bundle " + file); + final File file = RemoteOSGiActivator.getActivator().getContext() + .getDataFile("bundle_" + sourceID + ".jar"); + + final FileOutputStream fout = new FileOutputStream(file); + fout.write(bout.toByteArray()); + fout.close(); + System.err.println("Wrote proxy bundle to " + + file.getAbsolutePath()); } return new ByteArrayInputStream(bout.toByteArray()); @@ -384,7 +386,7 @@ class ProxyGenerator implements ClassVisitor, Opcodes { // like java.io.Serializable (or other classes // provided by the JRE). // (see https://bugs.eclipse.org/420112) - classLoader = getClass().getClassLoader(); + classLoader = ClassLoader.getSystemClassLoader(); } reader = new ClassReader(classLoader.getResourceAsStream( superIface + ".class")); //$NON-NLS-1$ @@ -433,7 +435,8 @@ class ProxyGenerator implements ClassVisitor, Opcodes { || (smartProxyClassName == null && name .equals(serviceInterfaceNames[0].replace('.', '/')))) { - if (RemoteOSGiServiceImpl.PROXY_DEBUG) { + if (RemoteOSGiServiceImpl.PROXY_DEBUG + && RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log.log(LogService.LOG_DEBUG, "creating proxy class " + implName); //$NON-NLS-1$ } @@ -467,13 +470,11 @@ class ProxyGenerator implements ClassVisitor, Opcodes { } else { // we have an interface - writer - .visit( - (version >= V1_5 && RemoteOSGiServiceImpl.IS_JAVA5) ? V1_5 - : V1_2, ACC_PUBLIC + ACC_SUPER, - implName, null, - "java/lang/Object", serviceInterfaces); //$NON-NLS-1$ - if (RemoteOSGiServiceImpl.PROXY_DEBUG) { + writer.visit( + (version >= V1_5 && RemoteOSGiServiceImpl.IS_JAVA5) ? V1_5 + : V1_2, ACC_PUBLIC + ACC_SUPER, implName, null, + "java/lang/Object", serviceInterfaces); //$NON-NLS-1$ + if (RemoteOSGiServiceImpl.PROXY_DEBUG && RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log.log(LogService.LOG_DEBUG, "Creating Proxy Bundle from Interfaces " //$NON-NLS-1$ + Arrays.asList(serviceInterfaceNames)); diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteOSGiActivator.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteOSGiActivator.java index fcfdc9f32..e06b9c084 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteOSGiActivator.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteOSGiActivator.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2006-2009 Jan S. Rellermeyer +/* Copyright (c) 2006-2010 Jan S. Rellermeyer * Systems Group, * Department of Computer Science, ETH Zurich. * All rights reserved. @@ -33,9 +33,7 @@ import java.util.Hashtable; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.service.log.LogService; - +import org.osgi.framework.BundleException; import ch.ethz.iks.r_osgi.RemoteOSGiService; import ch.ethz.iks.r_osgi.Remoting; import ch.ethz.iks.r_osgi.channels.NetworkChannelFactory; @@ -75,35 +73,35 @@ public final class RemoteOSGiActivator implements BundleActivator { * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */ public void start(final BundleContext context) throws Exception { - instance = this; - this.context = context; + try { + instance = this; + this.context = context; - // get the log service, if present - final ServiceReference logRef = context - .getServiceReference("org.osgi.service.log.LogService"); //$NON-NLS-1$ - if (logRef != null) { - RemoteOSGiServiceImpl.log = (LogService) context.getService(logRef); - } + if (remoting == null) { + // get the instance of RemoteOSGiServiceImpl + remoting = new RemoteOSGiServiceImpl(); + } - if (remoting == null) { - // get the instance of RemoteOSGiServiceImpl - remoting = new RemoteOSGiServiceImpl(); - } + // register the default tcp channel + if (!"false" //$NON-NLS-1$ + .equals(context + .getProperty(RemoteOSGiServiceImpl.REGISTER_DEFAULT_TCP_CHANNEL))) { + final Dictionary properties = new Hashtable(); + properties.put(NetworkChannelFactory.PROTOCOL_PROPERTY, + TCPChannelFactory.PROTOCOL); + context.registerService(NetworkChannelFactory.class.getName(), + new TCPChannelFactory(), properties); + } - // and register the service - context.registerService(new String[] { - RemoteOSGiService.class.getName(), Remoting.class.getName() }, remoting, null); + final Hashtable props = new Hashtable(); - // register the default tcp channel - if (!"false" //$NON-NLS-1$ - .equals(context - .getProperty(RemoteOSGiServiceImpl.REGISTER_DEFAULT_TCP_CHANNEL))) { - final Dictionary properties = new Hashtable(); - properties.put(NetworkChannelFactory.PROTOCOL_PROPERTY, - TCPChannelFactory.PROTOCOL); - context.registerService(NetworkChannelFactory.class.getName(), - new TCPChannelFactory(), properties); - // TODO: add default transport supported intents + // and register the service + context.registerService( + new String[] { RemoteOSGiService.class.getName(), + Remoting.class.getName() }, remoting, props); + } catch (final Throwable t) { + t.printStackTrace(); + throw new BundleException("Exception while starting R-OSGi", t); } } diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteOSGiServiceImpl.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteOSGiServiceImpl.java index df0292fe8..9c747230a 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteOSGiServiceImpl.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteOSGiServiceImpl.java @@ -52,6 +52,7 @@ import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.zip.CRC32; +import org.objectweb.asm.Type; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; @@ -62,6 +63,7 @@ import org.osgi.service.event.EventAdmin; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; import org.osgi.service.log.LogService; +import org.osgi.service.packageadmin.ExportedPackage; import org.osgi.service.packageadmin.PackageAdmin; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; @@ -128,8 +130,15 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { getEntry = m; getEntryPaths = n; - base = getEntry == null ? RemoteOSGiActivator.getActivator() - .getContext().getDataFile("../..") : null; + File b = null; + try { + b = getEntry == null ? RemoteOSGiActivator.getActivator() + .getContext().getDataFile("../..").getCanonicalFile() + : null; + } catch (IOException ioe) { + ioe.printStackTrace(); + } + base = b; } /** @@ -195,7 +204,7 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { * how many worker threads per endpoint? */ static final int MAX_THREADS_PER_ENDPOINT = Integer.getInteger( - THREADS_PER_ENDPOINT, 2).intValue(); + THREADS_PER_ENDPOINT, 16).intValue(); /** * log proxy generation debug output. @@ -233,6 +242,11 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { static LogService log; /** + * + */ + static ServiceTracker logServiceTracker; + + /** * the event admin tracker */ static ServiceTracker eventAdminTracker; @@ -271,7 +285,7 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { * Channel ID --> ChannelEndpointMultiplexer */ private static Map multiplexers = new HashMap(0); - + /** * Event topics this instance is going to ignore and not remote */ @@ -312,6 +326,28 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { // set the debug switches final BundleContext context = RemoteOSGiActivator.getActivator() .getContext(); + + logServiceTracker = new ServiceTracker(context, + LogService.class.getName(), new ServiceTrackerCustomizer() { + + public Object addingService(ServiceReference reference) { + System.err.println("LOG SERVICE ATTACHED"); + log = (LogService) context.getService(reference); + return log; + } + + public void modifiedService(ServiceReference reference, + Object service) { + + } + + public void removedService(ServiceReference reference, + Object service) { + log = (LogService) logServiceTracker.getService(); + } + + }); + String prop = context.getProperty(PROXY_DEBUG_PROPERTY); PROXY_DEBUG = prop != null ? Boolean.valueOf(prop).booleanValue() : false; @@ -333,10 +369,7 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { } else { if (PROXY_DEBUG || MSG_DEBUG || DEBUG) { System.err - .println("WARNING: NO LOG SERVICE PRESENT, DEBUG PROPERTIES HAVE NO EFFECT ..."); //$NON-NLS-1$ - PROXY_DEBUG = false; - MSG_DEBUG = false; - DEBUG = false; + .println("WARNING: NO LOG SERVICE PRESENT, DEBUG PROPERTIES HAVE NO EFFECT UNTIL A LOG SERVICE HAS BEEN STARTED"); //$NON-NLS-1$ } } @@ -469,7 +502,7 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { }); eventHandlerTracker.open(); - if (DEBUG) { + if (DEBUG && log != null) { log.log(LogService.LOG_DEBUG, "Local topic space " //$NON-NLS-1$ + Arrays.asList(getTopics())); } @@ -573,6 +606,9 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { e.printStackTrace(); throw new RemoteOSGiException( "Cannot find class " + service, e); //$NON-NLS-1$ + } catch (final RemoteOSGiException r) { + r.printStackTrace(); + throw r; } } @@ -586,6 +622,7 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { final RemoteServiceRegistration reg = (RemoteServiceRegistration) serviceRegistrations .get(reference); + unregisterFromServiceDiscovery(reg); registerWithServiceDiscovery(reg); final LeaseUpdateMessage lu = new LeaseUpdateMessage(); @@ -638,9 +675,10 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { factory.activate(RemoteOSGiServiceImpl.this); } catch (final IOException ioe) { if (log != null) { - log.log(LogService.LOG_ERROR, ioe - .getMessage(), ioe); + log.log(LogService.LOG_ERROR, + ioe.getMessage(), ioe); } + ioe.printStackTrace(); } return factory; } @@ -712,7 +750,9 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { final ChannelEndpointImpl test = (ChannelEndpointImpl) channels .get(endpoint.toString()); if (test != null) { - test.usageCounter++; + synchronized (test) { + test.usageCounter++; + } return test.getAllRemoteReferences(null); } @@ -746,12 +786,19 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { final ChannelEndpointImpl channel = (ChannelEndpointImpl) channels .get(channelURI); if (channel != null) { - if (channel.usageCounter == 1) { - channel.dispose(); - multiplexers.remove(channelURI); - } else { - channel.usageCounter--; + synchronized (channel) { + if (channel.usageCounter == 1) { + channel.dispose(); + multiplexers.remove(channelURI); + } else { + channel.usageCounter--; + } } + } else { + // TODO: to log + System.err.println("No channel " + endpoint + " to close (" + + channelURI + ")"); + System.err.println("channels " + channels); } } @@ -1077,6 +1124,7 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { */ static void unregisterChannelEndpoint(final String channelURI) { channels.remove(channelURI); + multiplexers.remove(channelURI); } /** @@ -1144,16 +1192,16 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { void registerWithServiceDiscovery(final RemoteServiceRegistration reg) { // register the service with all service // discovery handler + final Dictionary props = reg.getProperties(); final Object[] handler = serviceDiscoveryHandlerTracker.getServices(); if (handler != null) { for (int i = 0; i < handler.length; i++) { - final Dictionary props = reg.getProperties(); - ((ServiceDiscoveryHandler) handler[i]).registerService(reg - .getReference(), props, URI.create("r-osgi://" //$NON-NLS-1$ - + RemoteOSGiServiceImpl.MY_ADDRESS + ":" //$NON-NLS-1$ - + RemoteOSGiServiceImpl.R_OSGI_PORT + "#" //$NON-NLS-1$ - + reg.getServiceID())); + ((ServiceDiscoveryHandler) handler[i]).registerService( + reg.getReference(), props, URI.create("r-osgi://" //$NON-NLS-1$ + + RemoteOSGiServiceImpl.MY_ADDRESS + ":" //$NON-NLS-1$ + + RemoteOSGiServiceImpl.R_OSGI_PORT + "#" //$NON-NLS-1$ + + reg.getServiceID())); } } @@ -1200,6 +1248,50 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { } } + static String[] getMissingPackages(final String[] packages) { + final List missing = new ArrayList(); + for (int i = 0; i < packages.length; i++) { + if (getBundleForPackage(packages[i]) == null) { + missing.add(packages[i]); + } + } + return (String[]) missing.toArray(new String[missing.size()]); + + } + + private static Bundle getBundleForPackage(final String packageStr) { + ExportedPackage pkg = null; + final String pkgString; + String versionString = null; + final String[] tokens = StringUtils.splitString(packageStr, ";"); + pkgString = tokens[0]; + for (int j = 0; j < tokens.length; j++) { + if (tokens[j].startsWith("version")) { + versionString = tokens[j].substring("version=".length()); + break; + } + } + if (RemoteOSGiServiceImpl.IS_R4 && versionString != null) { + final ExportedPackage[] pkgs = pkgAdmin + .getExportedPackages(pkgString); + if (pkgs == null) { + return null; + } + for (int j = 0; j < pkgs.length; j++) { + final boolean matches = StringUtils.isVersionInRange( + pkgs[j].getVersion(), versionString); + if (matches + && (pkg == null || pkgs[j].getVersion().compareTo( + pkg.getVersion()) > 0)) { + pkg = pkgs[j]; + } + } + } else { + pkg = pkgAdmin.getExportedPackage(pkgString); + } + return pkg == null ? null : pkg.getExportingBundle(); + } + static byte[][] getBundlesForPackages(final String[] packages) throws IOException { final HashSet visitedBundles = new HashSet(packages.length); @@ -1214,10 +1306,9 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { BUFFER_SIZE) : null; - // TODO: for R4, handle multiple versions for (int i = 0; i < packages.length; i++) { - final Bundle bundle = pkgAdmin.getExportedPackage(packages[i]) - .getExportingBundle(); + final Bundle bundle = getBundleForPackage(packages[i]); + if (visitedBundles.contains(bundle)) { continue; } @@ -1260,14 +1351,6 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { return out.toByteArray(); } - static boolean checkPackageImport(final String pkg) { - // TODO: use versions if on R4 - if (pkg.startsWith("org.osgi")) { - return true; - } - return pkgAdmin.getExportedPackage(pkg) != null; - } - private static byte[] generateBundle(final Bundle bundle, final String prefix, final byte[] buffer, final CRC32 crc) throws Exception { @@ -1305,7 +1388,7 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { } else if (entry.endsWith(SEPARATOR_CHAR)) { scan(bundle, prefix, entry, out, buffer, crc); } else { - final URL url = bundle.getResource(prefix + "/" + entry); + final URL url = bundle.getEntry(prefix + "/" + entry); final InputStream in = url.openStream(); int read; int totallyRead = 0; @@ -1357,4 +1440,10 @@ final class RemoteOSGiServiceImpl implements RemoteOSGiService, Remoting { callback); } + public void asyncRemoteCall(final URI service, final Method method, + final Object[] args, final AsyncRemoteCallCallback callback) { + asyncRemoteCall(service, Type.getMethodDescriptor(method), args, + callback); + } + } diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteServiceReferenceImpl.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteServiceReferenceImpl.java index e0e0184e4..a97695faf 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteServiceReferenceImpl.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteServiceReferenceImpl.java @@ -33,6 +33,9 @@ import java.util.Arrays; import java.util.Dictionary; import java.util.Enumeration; +import org.osgi.framework.Constants; + +import ch.ethz.iks.r_osgi.RemoteOSGiService; import ch.ethz.iks.r_osgi.RemoteServiceReference; import ch.ethz.iks.r_osgi.URI; @@ -85,9 +88,16 @@ final class RemoteServiceReferenceImpl implements RemoteServiceReference { final String serviceID, final Dictionary properties, final ChannelEndpointImpl channel) { this.serviceInterfaces = serviceInterfaces; - this.properties = properties; - this.uri = channel.getRemoteAddress().resolve("#" + serviceID); //$NON-NLS-1$ + uri = channel.getRemoteAddress().resolve("#" + serviceID); //$NON-NLS-1$ this.properties = properties; + // adjust the properties + this.properties.put(RemoteOSGiService.SERVICE_URI, uri.toString()); + // remove the service PID, if set + this.properties.remove(Constants.SERVICE_PID); + // remove the R-OSGi registration property + this.properties.remove(RemoteOSGiService.R_OSGi_REGISTRATION); + // also remote the ECF registration property + this.properties.remove("org.eclipse.ecf.serviceRegistrationRemote"); //$NON-NLS-1$ this.channel = channel; } diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteServiceRegistration.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteServiceRegistration.java index 4deafe168..0f3c5cb35 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteServiceRegistration.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/RemoteServiceRegistration.java @@ -28,6 +28,7 @@ */ package ch.ethz.iks.r_osgi.impl; +import java.io.IOException; import java.lang.reflect.Method; import java.util.Dictionary; import java.util.HashMap; @@ -38,6 +39,7 @@ import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.service.log.LogService; +import ch.ethz.iks.r_osgi.RemoteOSGiException; import ch.ethz.iks.r_osgi.RemoteOSGiService; import ch.ethz.iks.r_osgi.messages.DeliverServiceMessage; @@ -76,7 +78,7 @@ final class RemoteServiceRegistration { /** * a prefactored deliver service message. */ - private DeliverServiceMessage deliverServiceMessage; + private volatile DeliverServiceMessage deliverServiceMessage; /** * creates a new RemoteService object. @@ -115,6 +117,11 @@ final class RemoteServiceRegistration { // build up the method table for each interface for (int i = 0; i < interfaceCount; i++) { serviceInterfaces[i] = bundleLoader.loadClass(interfaceNames[i]); + if (!serviceInterfaces[i].isInterface()) { + throw new RemoteOSGiException( + "Service registered under non-interface " + + serviceInterfaces[i].getName()); + } final Method[] methods = serviceInterfaces[i].getMethods(); for (int j = 0; j < methods.length; j++) { methodTable.put(methods[j].getName() @@ -126,19 +133,40 @@ final class RemoteServiceRegistration { final CodeAnalyzer analyzer = new CodeAnalyzer(bundleLoader, (String) headers.get(Constants.IMPORT_PACKAGE), (String) headers.get(Constants.EXPORT_PACKAGE)); - try { - deliverServiceMessage = analyzer.analyze(interfaceNames, - (String) ref.getProperty(RemoteOSGiService.SMART_PROXY), - (String[]) ref.getProperty(RemoteOSGiService.INJECTIONS), - (String) ref.getProperty(RemoteOSGiService.PRESENTATION)); - deliverServiceMessage.setServiceID(((Long) ref - .getProperty(Constants.SERVICE_ID)).toString()); - } catch (final Exception e) { - if (RemoteOSGiServiceImpl.log != null) { - RemoteOSGiServiceImpl.log.log(LogService.LOG_ERROR, - "Error during remote service registration", e); //$NON-NLS-1$ + new Thread() { + public void run() { + synchronized (RemoteServiceRegistration.this) { + try { + deliverServiceMessage = analyzer + .analyze( + interfaceNames, + (String) ref + .getProperty(RemoteOSGiService.SMART_PROXY), + (String[]) ref + .getProperty(RemoteOSGiService.INJECTIONS), + (String) ref + .getProperty(RemoteOSGiService.PRESENTATION)); + deliverServiceMessage.setServiceID(((Long) ref + .getProperty(Constants.SERVICE_ID)).toString()); + } catch (final IOException e) { + e.printStackTrace(); + if (RemoteOSGiServiceImpl.log != null) { + RemoteOSGiServiceImpl.log + .log(LogService.LOG_ERROR, + "Error during remote service registration", e); //$NON-NLS-1$ + } + } catch (final ClassNotFoundException cnf) { + cnf.printStackTrace(); + if (RemoteOSGiServiceImpl.log != null) { + RemoteOSGiServiceImpl.log + .log(LogService.LOG_ERROR, + "Error during remote service registration", cnf); //$NON-NLS-1$ + } + } + RemoteServiceRegistration.this.notifyAll(); + } } - } + }.start(); } /** @@ -239,7 +267,16 @@ final class RemoteServiceRegistration { * @return the message. */ DeliverServiceMessage getDeliverServiceMessage() { - return deliverServiceMessage; + synchronized (this) { + if (deliverServiceMessage == null) { + try { + wait(); + } catch (final InterruptedException e) { + // ignore + } + } + return deliverServiceMessage; + } } public String toString() { diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/TCPChannelFactory.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/TCPChannelFactory.java index a7eb1f72e..f5058c50e 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/TCPChannelFactory.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/impl/TCPChannelFactory.java @@ -36,6 +36,7 @@ import java.io.IOException; import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketException; import org.osgi.service.log.LogService; @@ -56,6 +57,8 @@ import ch.ethz.iks.util.SmartObjectOutputStream; */ final class TCPChannelFactory implements NetworkChannelFactory { + public static final boolean beSmart = true; + static final String PROTOCOL = "r-osgi"; //$NON-NLS-1$ Remoting remoting; private TCPAcceptorThread thread; @@ -93,8 +96,9 @@ final class TCPChannelFactory implements NetworkChannelFactory { * @see ch.ethz.iks.r_osgi.channels.NetworkChannelFactory#deactivate(ch.ethz.iks.r_osgi.Remoting) */ public void deactivate(final Remoting r) throws IOException { - if(thread != null) { - thread.interrupt(); + if (thread != null) { + thread.close(); + thread = null; } remoting = null; } @@ -219,11 +223,17 @@ final class TCPChannelFactory implements NetworkChannelFactory { // for 1.2 VMs that do not support the setKeepAlive } socket.setTcpNoDelay(true); - output = new SmartObjectOutputStream(new BufferedOutputStream( - socket.getOutputStream())); - output.flush(); - input = new SmartObjectInputStream(new BufferedInputStream(socket - .getInputStream())); + if (beSmart) { + output = new SmartObjectOutputStream(socket.getOutputStream()); + output.flush(); + input = new SmartObjectInputStream(socket.getInputStream()); + } else { + output = new ObjectOutputStream(new BufferedOutputStream( + socket.getOutputStream())); + output.flush(); + input = new ObjectInputStream(new BufferedInputStream( + socket.getInputStream())); + } } /** @@ -284,7 +294,7 @@ final class TCPChannelFactory implements NetworkChannelFactory { */ public void sendMessage(final RemoteOSGiMessage message) throws IOException { - if (RemoteOSGiServiceImpl.MSG_DEBUG) { + if (RemoteOSGiServiceImpl.MSG_DEBUG && RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log.log(LogService.LOG_DEBUG, "{TCP Channel} sending " + message); //$NON-NLS-1$ } @@ -309,7 +319,7 @@ final class TCPChannelFactory implements NetworkChannelFactory { try { final RemoteOSGiMessage msg = RemoteOSGiMessage .parse(input); - if (RemoteOSGiServiceImpl.MSG_DEBUG) { + if (RemoteOSGiServiceImpl.MSG_DEBUG && RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log.log(LogService.LOG_DEBUG, "{TCP Channel} received " + msg); //$NON-NLS-1$ } @@ -365,6 +375,11 @@ final class TCPChannelFactory implements NetworkChannelFactory { RemoteOSGiServiceImpl.R_OSGI_PORT = listeningPort; return; } catch (final BindException b) { + // normal behavior, get a BindException if the port is + // already in use + e++; + } catch (final SocketException s) { + // Windows 7 behavior e++; } } @@ -382,10 +397,15 @@ final class TCPChannelFactory implements NetworkChannelFactory { // for them remoting.createEndpoint(new TCPChannel(socket.accept())); } catch (final IOException ioe) { - ioe.printStackTrace(); + // TODO: to log } } } + + public void close() throws IOException { + interrupt(); + socket.close(); + } } } diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/messages/DeliverServiceMessage.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/messages/DeliverServiceMessage.java index 8e541cf90..5ca32f72a 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/messages/DeliverServiceMessage.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/messages/DeliverServiceMessage.java @@ -173,7 +173,6 @@ public final class DeliverServiceMessage extends RemoteOSGiMessage { + pkgName + ";resolution:=optional"; } } - } /** diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/messages/RemoteOSGiMessage.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/messages/RemoteOSGiMessage.java index bc36e040e..5187b24fa 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/messages/RemoteOSGiMessage.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/r_osgi/messages/RemoteOSGiMessage.java @@ -258,7 +258,7 @@ public abstract class RemoteOSGiMessage { out.write(funcID); out.writeInt(xid); writeBody(out); - out.reset(); + //out.reset(); out.flush(); } } diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectInputStream.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectInputStream.java index 8a28c1b4d..469461fbb 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectInputStream.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectInputStream.java @@ -32,9 +32,9 @@ package ch.ethz.iks.util; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; +import java.lang.reflect.Method; +import java.util.zip.GZIPInputStream; /** * Smart object input stream that is able to deserialize classes which do not @@ -46,251 +46,50 @@ import java.lang.reflect.Modifier; */ public final class SmartObjectInputStream extends ObjectInputStream { - private final ObjectInputStream in; + private Object handles; + private Field handle; + private Method setHandle; public SmartObjectInputStream(final InputStream in) throws IOException { - // implicitly: super(); - // thereby, enableOverride is set - this.in = new ObjectInputStream(in); + super(new GZIPInputStream(in)); + enableResolveObject(true); + try { + final Field field = getClass().getSuperclass().getDeclaredField( + "handles"); + field.setAccessible(true); + handles = field.get(this); + handle = getClass().getSuperclass().getDeclaredField("passHandle"); + handle.setAccessible(true); + setHandle = handles.getClass().getDeclaredMethod("setObject", + new Class[] { Integer.TYPE, Object.class }); + setHandle.setAccessible(true); + } catch (Exception e) { + // handle replacement won't work. + } } - protected final Object readObjectOverride() throws IOException, - ClassNotFoundException { - - final byte cat = in.readByte(); - switch (cat) { - case 0: - // null - return null; - case 1: - // string serialized object - // TODO: cache constructors + protected Object resolveObject(final Object obj) throws IOException { + if (obj instanceof SmartObjectStreamClass) { try { - final String type = in.readUTF(); - final Class test = (Class) SmartConstants.idToClass.get(type); - final Class clazz = test != null ? test : Class.forName(type); - final Constructor constr = clazz - .getConstructor(new Class[] { String.class }); - return constr.newInstance(new Object[] { in.readUTF() }); - } catch (final Exception e) { - e.printStackTrace(); - throw new IOException(e.getMessage()); - } - case 2: - // java serialized object - return in.readObject(); - case 3: - return readSmartSerializedObject(); - case 4: - final int length = in.readByte(); - final String clazzName = in.readUTF(); - final Class clazz = Class.forName(clazzName); - final Object[] array = (Object[]) java.lang.reflect.Array - .newInstance(clazz, length); - for (int i = 0; i < length; i++) { - final byte b = in.readByte(); - if(b == -1) { - array[i] = null; - } else { - array[i] = readSmartSerializedObject(); - } + return ((SmartObjectStreamClass) obj).restoreObject(); + } catch (Exception e) { + final IOException f = new IOException( + "Exception while resolving object"); + f.initCause(e); + throw f; } - return array; - default: - throw new IllegalStateException("Unhandled case " + cat); //$NON-NLS-1$ } + return obj; } - private Object readSmartSerializedObject() throws IOException, ClassNotFoundException { - // smart serialized object - final String clazzName = in.readUTF(); - - // TODO: cache this information... - Class clazz = Class.forName(clazzName); - + void fixHandle(final Object obj) { + if (setHandle == null) { + return; + } try { - final Constructor constr = clazz.getDeclaredConstructor(null); - constr.setAccessible(true); - final Object newInstance = constr.newInstance(null); - - int fieldCount = in.readInt(); - while (fieldCount > -1) { - for (int i = 0; i < fieldCount; i++) { - final String fieldName = in.readUTF(); - final Object value = readObjectOverride(); - final Field field = clazz.getDeclaredField(fieldName); - - final int mod = field.getModifiers(); - if (!Modifier.isPublic(mod)) { - field.setAccessible(true); - } - - field.set(newInstance, value); - } - clazz = clazz.getSuperclass(); - fieldCount = in.readInt(); - } - return newInstance; - } catch (final Exception e) { + setHandle.invoke(handles, new Object[] { handle.get(this), obj }); + } catch (Exception e) { e.printStackTrace(); - throw new IOException("Error while deserializing " + clazzName //$NON-NLS-1$ - + ": " + e.getMessage()); //$NON-NLS-1$ } } - - /** - * - * @see java.io.ObjectInputStream#read() - */ - public final int read() throws IOException { - return in.read(); - } - - /** - * - * @see java.io.ObjectInputStream#read(byte[], int, int) - */ - public final int read(final byte[] buf, final int off, final int len) - throws IOException { - return in.read(buf, off, len); - } - - /** - * - * @see java.io.ObjectInputStream#available() - */ - public final int available() throws IOException { - return in.available(); - } - - /** - * - * @see java.io.ObjectInputStream#close() - */ - public final void close() throws IOException { - in.close(); - } - - /** - * - * @see java.io.ObjectInputStream#readBoolean() - */ - public final boolean readBoolean() throws IOException { - return in.readBoolean(); - } - - /** - * - * @see java.io.ObjectInputStream#readByte() - */ - public final byte readByte() throws IOException { - return in.readByte(); - } - - /** - * - * @see java.io.ObjectInputStream#readUnsignedByte() - */ - public final int readUnsignedByte() throws IOException { - return in.readUnsignedByte(); - } - - /** - * - * @see java.io.ObjectInputStream#readChar() - */ - public final char readChar() throws IOException { - return in.readChar(); - } - - /** - * - * @see java.io.ObjectInputStream#readShort() - */ - public final short readShort() throws IOException { - return in.readShort(); - } - - /** - * - * @see java.io.ObjectInputStream#readUnsignedShort() - */ - public final int readUnsignedShort() throws IOException { - return in.readUnsignedShort(); - } - - /** - * - * @see java.io.ObjectInputStream#readInt() - */ - public final int readInt() throws IOException { - return in.readInt(); - } - - /** - * - * @see java.io.ObjectInputStream#readLong() - */ - public final long readLong() throws IOException { - return in.readLong(); - } - - /** - * - * @see java.io.ObjectInputStream#readFloat() - */ - public final float readFloat() throws IOException { - return in.readFloat(); - } - - /** - * - * @see java.io.ObjectInputStream#readDouble() - */ - public final double readDouble() throws IOException { - return in.readDouble(); - } - - /** - * - * @see java.io.ObjectInputStream#readFully(byte[]) - */ - public final void readFully(final byte[] buf) throws IOException { - in.readFully(buf); - } - - /** - * - * @see java.io.ObjectInputStream#readFully(byte[], int, int) - */ - public final void readFully(final byte[] buf, final int off, final int len) - throws IOException { - in.readFully(buf, off, len); - } - - /** - * - * @see java.io.ObjectInputStream#skipBytes(int) - */ - public final int skipBytes(final int len) throws IOException { - return in.skipBytes(len); - } - - /** - * @return String - * @throws IOException - * @deprecated - */ - public final String readLine() throws IOException { - return in.readLine(); - } - - /** - * - * @see java.io.ObjectInputStream#readUTF() - */ - public final String readUTF() throws IOException { - return in.readUTF(); - } - } diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectOutputStream.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectOutputStream.java index d352af1d0..0899636a6 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectOutputStream.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectOutputStream.java @@ -1,6 +1,5 @@ -/* Copyright (c) 2006-2009 Jan S. Rellermeyer - * Systems Group, - * Institute for Pervasive Computing, ETH Zurich. +/* Copyright (c) 2006-2011 Jan S. Rellermeyer + * Systems Group, ETH Zurich. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,9 +33,10 @@ import java.io.NotSerializableException; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.Set; +import java.util.zip.Deflater; +import java.util.zip.GZIPOutputStream; import ch.ethz.iks.r_osgi.types.BoxedPrimitive; @@ -46,269 +46,80 @@ import ch.ethz.iks.r_osgi.types.BoxedPrimitive; * and the OSGi ServiceReference and ServiceRegistration classes. * * @author Jan S. Rellermeyer - * */ public final class SmartObjectOutputStream extends ObjectOutputStream { - private final ObjectOutputStream out; + static Set blackList = new HashSet(); + static { + blackList.add("org.osgi.framework.ServiceReference"); //$NON-NLS-1$ + blackList.add("org.osgi.framework.ServiceRegistration"); //$NON-NLS-1$ + } public SmartObjectOutputStream(final OutputStream out) throws IOException { - // implicitly: super(); - // thereby, enableOverride is set - this.out = new ObjectOutputStream(out); + super(new EnhancedGZIPOutputStream(out)); + this.enableReplaceObject(true); } - protected final void writeObjectOverride(final Object o) throws IOException { - if (o == null) { - out.writeByte(0); - return; + protected Object replaceObject(final Object obj) throws IOException { + if (obj instanceof BoxedPrimitive) { + return ((BoxedPrimitive) obj).getBoxed(); } - final Object obj = o instanceof BoxedPrimitive ? ((BoxedPrimitive) o) - .getBoxed() : o; - - final String clazzName = obj.getClass().getName(); - if (SmartConstants.positiveList.contains(clazzName)) { - // string serializable classes - out.writeByte(1); - final String id = (String) SmartConstants.classToId.get(clazzName); - out.writeUTF(id != null ? id : clazzName); - out.writeUTF(obj.toString()); - return; - } else if (isNestedSmartSerializedObject(obj)) { - final Object[] objArray = (Object[]) obj; - final String clazzname = objArray.getClass().getName(); - out.write(4); - out.writeByte(objArray.length); - out.writeUTF(clazzname.substring(2, clazzname.length() - 1)); - for (int i = 0; i < objArray.length; i++) { - final Object elem = objArray[i]; - if(elem == null) { - out.writeByte(-1); - } else { - writeSmartSerializedObject(elem); - } - } - } else if (obj instanceof Serializable) { - // java serializable classes - out.writeByte(2); - out.writeObject(obj); - return; - } else { - writeSmartSerializedObject(obj); + if (obj instanceof Serializable) { + return obj; } - } - private boolean isNestedSmartSerializedObject(final Object obj) { - if(obj != null && obj instanceof Object[]) { - Object[] objArray = (Object[]) obj; - if(objArray.length > 0) { - // iterate to skip null - for(int i = 0; i < objArray.length; i++) { - if(objArray[i] instanceof Serializable) { - return false; - } - } - return true; - } + final Class clazz = obj.getClass(); + if (blackList.contains(clazz.getName())) { + throw new NotSerializableException(clazz.getName()); } - return false; + + return new SmartObjectStreamClass(obj, clazz); } - private void writeSmartSerializedObject(final Object obj) throws IOException, - NotSerializableException { - out.writeByte(3); + static class EnhancedGZIPOutputStream extends GZIPOutputStream { - // all other classes: try smart serialization - Class clazz = obj.getClass(); + private static final byte[] NOTHING = new byte[0]; + private boolean hasPendingBytes = false; - if (SmartConstants.blackList.contains(clazz.getName())) { - throw new NotSerializableException("Class " + clazz.getName() //$NON-NLS-1$ - + " is not serializable"); //$NON-NLS-1$ + public EnhancedGZIPOutputStream(final OutputStream out) + throws IOException { + super(out); + def.setLevel(Deflater.BEST_SPEED); } - out.writeUTF(clazz.getName()); - - // TODO: cache this information... - while (clazz != Object.class) { - // check for native methods - final Method[] methods = clazz.getDeclaredMethods(); - for (int j = 0; j < methods.length; j++) { - final int mod = methods[j].getModifiers(); - if (Modifier.isNative(mod)) { - throw new NotSerializableException( - "Class " //$NON-NLS-1$ - + clazz.getName() - + " contains native methods and is therefore not serializable."); //$NON-NLS-1$ - } - } + public void write(final byte[] bytes, final int i, final int i1) + throws IOException { + super.write(bytes, i, i1); + hasPendingBytes = true; + } - try { - final Field[] fields = clazz.getDeclaredFields(); - final int fieldCount = fields.length; - int realFieldCount = 0; - for (int i = 0; i < fieldCount; i++) { - final int mod = fields[i].getModifiers(); - if (!(Modifier.isStatic(mod) || Modifier.isTransient(mod))) { - realFieldCount++; - } - } - out.writeInt(realFieldCount); - for (int i = 0; i < fieldCount; i++) { - final int mod = fields[i].getModifiers(); - if (Modifier.isStatic(mod) || Modifier.isTransient(mod)) { - continue; - } else if (!Modifier.isPublic(mod)) { - fields[i].setAccessible(true); - } - out.writeUTF(fields[i].getName()); - writeObjectOverride(fields[i].get(obj)); + protected void deflate() throws IOException { + int len; + do { + len = def.deflate(buf, 0, buf.length); + if (len == 0) { + break; } - } catch (final Exception e) { - throw new NotSerializableException( - "Exception while serializing " + obj.toString() //$NON-NLS-1$ - + ":\n" + e.getMessage()); //$NON-NLS-1$ - } - clazz = clazz.getSuperclass(); + this.out.write(buf, 0, len); + } while (true); } - out.writeInt(-1); - } - - /** - * - * @see java.io.ObjectOutputStream#write(int) - */ - public final void write(final int val) throws IOException { - out.write(val); - } - - /** - * - * @see java.io.ObjectOutputStream#write(byte[]) - */ - public final void write(final byte[] buf) throws IOException { - out.write(buf); - } - - /** - * - * @see java.io.ObjectOutputStream#write(byte[], int, int) - */ - public final void write(final byte[] buf, final int off, final int len) - throws IOException { - out.write(buf, off, len); - } - - /** - * - * @see java.io.ObjectOutputStream#flush() - */ - public final void flush() throws IOException { - out.flush(); - } - - /** - * - * @see java.io.ObjectOutputStream#reset() - */ - public final void reset() throws IOException { - out.reset(); - } - /** - * - * @see java.io.ObjectOutputStream#close() - */ - public final void close() throws IOException { - out.close(); - } - - /** - * - * @see java.io.ObjectOutputStream#writeBoolean(boolean) - */ - public final void writeBoolean(final boolean val) throws IOException { - out.writeBoolean(val); - } - - /** - * - * @see java.io.ObjectOutputStream#writeByte(int) - */ - public final void writeByte(final int val) throws IOException { - out.writeByte(val); - } - - /** - * - * @see java.io.ObjectOutputStream#writeShort(int) - */ - public final void writeShort(final int val) throws IOException { - out.writeShort(val); - } - - /** - * - * @see java.io.ObjectOutputStream#writeChar(int) - */ - public final void writeChar(final int val) throws IOException { - out.writeChar(val); - } - - /** - * - * @see java.io.ObjectOutputStream#writeInt(int) - */ - public final void writeInt(final int val) throws IOException { - out.writeInt(val); - } - - /** - * - * @see java.io.ObjectOutputStream#writeLong(long) - */ - public final void writeLong(final long val) throws IOException { - out.writeLong(val); - } - - /** - * - * @see java.io.ObjectOutputStream#writeFloat(float) - */ - public final void writeFloat(final float val) throws IOException { - out.writeFloat(val); - } - - /** - * - * @see java.io.ObjectOutputStream#writeDouble(double) - */ - public final void writeDouble(final double val) throws IOException { - out.writeDouble(val); - } - - /** - * - * @see java.io.ObjectOutputStream#writeBytes(java.lang.String) - */ - public final void writeBytes(final String str) throws IOException { - out.writeBytes(str); - } + public void flush() throws IOException { + if (!hasPendingBytes) { + return; + } - /** - * - * @see java.io.ObjectOutputStream#writeChars(java.lang.String) - */ - public final void writeChars(final String str) throws IOException { - out.writeChars(str); - } + if (!def.finished()) { + def.setInput(NOTHING, 0, 0); + def.setLevel(Deflater.NO_COMPRESSION); + deflate(); + def.setLevel(Deflater.BEST_SPEED); + deflate(); + super.flush(); + } - /** - * - * @see java.io.ObjectOutputStream#writeUTF(java.lang.String) - */ - public final void writeUTF(final String str) throws IOException { - out.writeUTF(str); + hasPendingBytes = false; + } } - } diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectStreamClass.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectStreamClass.java new file mode 100644 index 000000000..ba8e74b1b --- /dev/null +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/SmartObjectStreamClass.java @@ -0,0 +1,150 @@ +package ch.ethz.iks.util; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.WeakHashMap; + +public class SmartObjectStreamClass implements Externalizable { + + private String clazzName; + private String[] fieldNames; + private Object[] fieldValues; + private SmartObjectStreamClass superStreamClass; + private transient Object restored; + + static final WeakHashMap fieldInfoCache = new WeakHashMap(); + + public SmartObjectStreamClass(final Object obj, final Class clazz) + throws NotSerializableException { + + clazzName = clazz.getName(); + + final String[] fieldInfo = (String[]) fieldInfoCache.get(clazzName); + + final Field[] fields = clazz.getDeclaredFields(); + final int fieldCount = fields.length; + + try { + if (fieldInfo == null) { + // check for native methods + final Method[] methods = clazz.getDeclaredMethods(); + for (int i = 0; i < methods.length; i++) { + final int mod = methods[i].getModifiers(); + if (Modifier.isNative(mod)) { + SmartObjectOutputStream.blackList.add(clazz); + throw new NotSerializableException( + "Class " //$NON-NLS-1$ + + clazz.getName() + + " contains native methods and is therefore not serializable."); //$NON-NLS-1$ + } + } + + int realFieldCount = 0; + for (int i = 0; i < fieldCount; i++) { + final int mod = fields[i].getModifiers(); + if (!(Modifier.isStatic(mod) || Modifier.isTransient(mod))) { + realFieldCount++; + } + } + fieldNames = new String[realFieldCount]; + fieldInfoCache.put(clazzName, fieldNames); + } else { + fieldNames = fieldInfo; + } + + fieldValues = new Object[fieldNames.length]; + + for (int i = 0; i < fieldCount; i++) { + final int mod = fields[i].getModifiers(); + if (Modifier.isStatic(mod) || Modifier.isTransient(mod)) { + continue; + } else if (!Modifier.isPublic(mod)) { + fields[i].setAccessible(true); + } + fieldNames[i] = fields[i].getName(); + fieldValues[i] = fields[i].get(obj); + } + } catch (final Exception e) { + SmartObjectOutputStream.blackList.add(clazz); + throw new NotSerializableException( + "Exception while serializing " + obj.toString() //$NON-NLS-1$ + + ":\n" + e.getMessage()); //$NON-NLS-1$ + } + + final Class superClazz = clazz.getSuperclass(); + if (superClazz != null && superClazz != Object.class) { + superStreamClass = new SmartObjectStreamClass(obj, superClazz); + } + } + + public SmartObjectStreamClass() { + + } + + public void writeExternal(final ObjectOutput out) throws IOException { + out.writeUTF(clazzName); + out.writeInt(fieldNames.length); + for (int i = 0; i < fieldNames.length; i++) { + out.writeUTF(fieldNames[i]); + out.writeObject(fieldValues[i]); + } + } + + public void readExternal(final ObjectInput in) throws IOException, + ClassNotFoundException { + clazzName = in.readUTF(); + + try { + final Class clazz = Class.forName(clazzName); + final Constructor constr = clazz.getDeclaredConstructor(null); + constr.setAccessible(true); + restored = constr.newInstance(null); + } catch (Exception e) { + final IOException f = new IOException( + "Exception while resolving object"); + f.initCause(e); + throw f; + } + + ((SmartObjectInputStream) in).fixHandle(restored); + + final int fieldCount = in.readInt(); + fieldNames = new String[fieldCount]; + fieldValues = new Object[fieldCount]; + for (int i = 0; i < fieldCount; i++) { + fieldNames[i] = in.readUTF(); + fieldValues[i] = in.readObject(); + } + } + + public Object restoreObject() throws Exception { + restoreFields(restored); + return restored; + } + + private void restoreFields(final Object o) throws Exception { + final Class clazz = Class.forName(clazzName); + for (int i = 0; i < fieldNames.length; i++) { + final Field field = clazz.getDeclaredField(fieldNames[i]); + + final int mod = field.getModifiers(); + if (!Modifier.isPublic(mod)) { + field.setAccessible(true); + } + + field.set(o, fieldValues[i]); + } + + if (superStreamClass != null) { + superStreamClass.restoreFields(o); + } + } + +} diff --git a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/StringUtils.java b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/StringUtils.java index 79f6bcec2..66b2a5c3a 100644 --- a/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/StringUtils.java +++ b/protocols/bundles/ch.ethz.iks.r_osgi.remote/src/main/java/ch/ethz/iks/util/StringUtils.java @@ -34,6 +34,8 @@ import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; +import org.osgi.framework.Version; + /** * String utilities. * @@ -48,6 +50,140 @@ public final class StringUtils { private StringUtils() { } + public static String[] splitString(final String values, + final String delimiter) throws IllegalArgumentException { + if (values == null) { + return new String[0]; + } + + final List tokens = new ArrayList(values.length() / 10); + int pointer = 0; + int quotePointer = 0; + int tokenStart = 0; + int nextDelimiter; + while ((nextDelimiter = values.indexOf(delimiter, pointer)) > -1) { + int openingQuote = values.indexOf("\"", quotePointer); + int closingQuote = values.indexOf("\"", openingQuote + 1); + if (openingQuote > closingQuote) { + throw new IllegalArgumentException( + "Missing closing quotation mark."); + } + if (openingQuote > -1 && openingQuote < nextDelimiter + && closingQuote < nextDelimiter) { + quotePointer = ++closingQuote; + continue; + } + if (openingQuote < nextDelimiter && nextDelimiter < closingQuote) { + pointer = ++closingQuote; + continue; + } + // TODO: for performance, fold the trim into the splitting + tokens.add(values.substring(tokenStart, nextDelimiter).trim()); + pointer = ++nextDelimiter; + quotePointer = pointer; + tokenStart = pointer; + } + tokens.add(values.substring(tokenStart).trim()); + return (String[]) tokens.toArray(new String[tokens.size()]); + } + + /** + * splits a parameter (directives or attributes) into key and value + * + * @param token + * @return The split string + * @throws IllegalArgumentException + */ + public static String[] splitParameter(final String token) + throws IllegalArgumentException { + int pos = token.indexOf(":="); + int offset = 2; + if (pos < 0) { + pos = token.indexOf("="); + if (pos < 0) { + throw new IllegalArgumentException("Malformed parameter " + + token); + } + offset = 1; + } + return new String[] { token.substring(0, pos), + unQuote(token.substring(pos + offset, token.length())) }; + } + + public static String unQuote(final String quoted) { + final int len = quoted.length(); + final int start = quoted.charAt(0) == '"' ? 1 : 0; + final int end = quoted.charAt(quoted.length() - 1) == '"' ? len - 1 + : len; + return (start == 0 && end == len) ? quoted : quoted.substring(start, + end); + } + + /** + * check, if the version is in the range of the version range specified by + * str + * + * @param version + * the Version to compare against the range + * @param str + * String, that describes the version range + * @return true, if version in range + */ + public static boolean isVersionInRange(Version version, String str) { + // System.out.println(" VERSION CHECK: "+version.toString()+" in range "+str+"?"); + + // parse range + if (str == null || str.length() < 1) { + return (version.compareTo(Version.emptyVersion) > -1); + } + + // remove " + if (str.startsWith("\"")) { + str = str.substring(1, str.length()); + } + if (str.endsWith("\"")) { + str = str.substring(0, str.length() - 1); + } + + final String[] bounds = splitString(str, ","); + if (bounds.length <= 1) { + // range is only an "atleast value" + Version v2 = new Version(str); + if (version.compareTo(v2) < 0) { + return false; + } + } else { + // range has lower and upper bound + final Version lower = new Version(bounds[0].substring(1).trim()); + final Version upper = new Version(bounds[1].substring(0, + bounds[1].length() - 1).trim()); + // check lower bound + if (bounds[0].startsWith("[")) { + if (version.compareTo(lower) < 0) { + return false; + } + } else { + // assume "(" + if (version.compareTo(lower) <= 0) { + return false; + } + } + // check upper bound + if (bounds[1].endsWith("]")) { + if (version.compareTo(upper) > 0) { + return false; + } + } else { + // assume ")" + if (version.compareTo(upper) >= 0) { + return false; + } + } + + } + return true; + } + /** * transforms a string list into an array of Strings. * |