/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG and others. * 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: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.internal.communication.factory.hessian; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.security.SecureRandom; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.riena.communication.core.IRemoteServiceReference; import org.eclipse.riena.communication.core.RemoteServiceDescription; import org.eclipse.riena.communication.core.factory.IRemoteServiceFactory; import org.eclipse.riena.communication.core.factory.RemoteServiceReference; import org.eclipse.riena.communication.core.hooks.ICallMessageContext; import org.eclipse.riena.communication.core.hooks.ICallMessageContextAccessor; import org.eclipse.riena.communication.core.progressmonitor.IRemoteProgressMonitorList; import org.eclipse.riena.communication.core.progressmonitor.IRemoteProgressMonitorRegistry; import org.eclipse.riena.core.wire.InjectExtension; import org.eclipse.riena.core.wire.InjectService; /** * This is a Hessian based implementation of {@link IRemoteServiceFactory}. * Creates RemoteServiceReferences for service end points based on Hessian * protocol. * <p> * RemoteServiceFactoryHessian becomes registered as OSGi Service with name * {@link IRemoteServiceFactory#ID}. The OSGi Service set the property * "riena.protocol=hessian". * */ public class RemoteServiceFactoryHessian implements IRemoteServiceFactory { private IRemoteProgressMonitorRegistry remoteProgressMonitorRegistry; private final ICallMessageContextAccessor messageContextAccessor; private final RienaHessianProxyFactory rienaHessianProxyFactory; private final static String PROTOCOL = "hessian"; //$NON-NLS-1$ private final static SecureRandom RANDOM = new SecureRandom(); private final static long BASE_LONG = 115825100000L; // some BASE_LONG time in millisec around 14.9.2006 18:40 (arbitrary picked) just to make the long a short number public RemoteServiceFactoryHessian() { messageContextAccessor = new CallMsgCtxAcc(); rienaHessianProxyFactory = new RienaHessianProxyFactory(); rienaHessianProxyFactory.setCallMessageContextAccessor(messageContextAccessor); } public IRemoteServiceReference createProxy(final RemoteServiceDescription endpoint) { String url = endpoint.getURL(); if (url == null) { url = "http://localhost/" + PROTOCOL + endpoint.getPath(); //$NON-NLS-1$ } try { final Object proxy = rienaHessianProxyFactory.create(endpoint.getServiceInterfaceClass(), url, new ClassLoader() { @Override public Class<?> loadClass(final String name) throws ClassNotFoundException { try { return endpoint.getServiceClassLoader().loadClass(name); } catch (final Throwable ex) { return getClass().getClassLoader().loadClass(name); } } }); final RemoteServiceReference serviceReference = new RemoteServiceReference(endpoint); // set the create proxy as service instance serviceReference.setServiceInstance(proxy); return serviceReference; } catch (final MalformedURLException e) { throw new RuntimeException("MalformedURLException for endpoint '" + endpoint + ".", e); //$NON-NLS-1$ //$NON-NLS-2$ } } @InjectExtension(min = 0, max = 1) public void update(final IRemoteServiceFactoryHessianExtension extension) { if (extension == null) { return; } rienaHessianProxyFactory.setZipClientRequest(extension.isZipClientRequest()); if (extension.getReadTimeout() > 0) { rienaHessianProxyFactory.setReadTimeout(extension.getReadTimeout()); } if (extension.getConnectTimeout() > 0) { rienaHessianProxyFactory.setConnectTimeout(extension.getConnectTimeout()); } } @InjectService(useRanking = true) public void bind(final IRemoteProgressMonitorRegistry pmr) { this.remoteProgressMonitorRegistry = pmr; } public void unbind(final IRemoteProgressMonitorRegistry pmr) { if (this.remoteProgressMonitorRegistry == pmr) { this.remoteProgressMonitorRegistry = null; } } public String getProtocol() { return PROTOCOL; } public ICallMessageContextAccessor getMessageContextAccessor() { return messageContextAccessor; } class CallMsgCtxAcc implements ICallMessageContextAccessor { private final ThreadLocal<ICallMessageContext> contexts = new ThreadLocal<ICallMessageContext>(); public ICallMessageContext createMessageContext(final Object proxy, final String methodName, final String requestId) { final ICallMessageContext mc = new MsgCtx(proxy, methodName, requestId); contexts.set(mc); return mc; } public ICallMessageContext getMessageContext() { return contexts.get(); } class MsgCtx implements ICallMessageContext { private HashMap<String, List<String>> customRequestHeader; private IRemoteProgressMonitorList remoteProgressMonitorList; private int bytesRead; private int totalBytesRead = 0; private int bytesWritten; private int totalBytesWritten = 0; private boolean firstEvent = true; private final String methodName; private String requestId = null; public MsgCtx(final Object proxy, final String methodName, final String requestId) { super(); this.methodName = methodName; this.requestId = requestId; if (remoteProgressMonitorRegistry != null) { remoteProgressMonitorList = remoteProgressMonitorRegistry.getProgressMonitors(proxy); } else { remoteProgressMonitorList = null; } } public List<String> getResponseHeaderValues(final String name) { final Map<String, List<String>> headers = listResponseHeaders(); if (headers == null) { return null; } return headers.get(name); } public Map<String, List<String>> listRequestHeaders() { return customRequestHeader; } public Map<String, List<String>> listResponseHeaders() { final HttpURLConnection httpUrlConnection = RienaHessianProxyFactory.getHttpURLConnection(); if (httpUrlConnection == null) { return null; } return httpUrlConnection.getHeaderFields(); } public void addRequestHeader(final String name, final String value) { if (customRequestHeader == null) { customRequestHeader = new HashMap<String, List<String>>(); } List<String> hValues = customRequestHeader.get(name); if (hValues == null) { hValues = new ArrayList<String>(); customRequestHeader.put(name, hValues); } hValues.add(value); } public IRemoteProgressMonitorList getProgressMonitorList() { return remoteProgressMonitorList; } public void fireStartCall() { // List<String> list = RienaHessianProxyFactory.getHttpURLConnection().getRequestProperties().get( // "Content-Length"); //$NON-NLS-1$ remoteProgressMonitorList.fireStartEvent(); firstEvent = false; } public void fireEndCall() { // if no communication happened than this was a local call (like for equals or hashCode) if (totalBytesRead == 0 && totalBytesWritten == 0 && bytesRead == 0 && bytesWritten == 0) { return; } if (bytesRead != 0) { internalFireReadEvent(); } remoteProgressMonitorList.fireEndEvent(totalBytesRead + totalBytesWritten); } public void fireReadEvent(final int parmBytesRead) { if (firstEvent) { remoteProgressMonitorList.fireStartEvent(); firstEvent = false; } if (bytesWritten != 0) { internalFireWriteEvent(); } bytesRead += parmBytesRead; if (bytesRead >= IRemoteProgressMonitorList.BYTE_COUNT_INCR) { internalFireReadEvent(); } } private void internalFireReadEvent() { totalBytesRead += bytesRead; bytesRead = 0; remoteProgressMonitorList.fireReadEvent(-1, totalBytesRead); } public void fireWriteEvent(final int parmBytesWritten) { if (firstEvent) { fireStartCall(); } bytesWritten += parmBytesWritten; if (bytesWritten >= IRemoteProgressMonitorList.BYTE_COUNT_INCR) { internalFireWriteEvent(); } } private void internalFireWriteEvent() { totalBytesWritten += bytesWritten; bytesWritten = 0; remoteProgressMonitorList.fireWriteEvent(-1, totalBytesWritten); } /* * (non-Javadoc) * * @see * org.eclipse.riena.communication.core.hooks.ICallMessageContext * #getMethodName() */ public String getMethodName() { return methodName; } /* * (non-Javadoc) * * @see * org.eclipse.riena.communication.core.hooks.ICallMessageContext * #getRequestId() */ public String getRequestId() { if (requestId == null || requestId.length() == 0) { // FINDBUGS: if RANDOM.nextInt()==Integer.MIN_VALUE then Math.abs(i) = i int i = RANDOM.nextInt(); if (i == Integer.MIN_VALUE) { i = i + 1; } requestId = "RID-" + Long.toString(System.currentTimeMillis() - BASE_LONG + Math.abs(i), 36); //$NON-NLS-1$ } return requestId; } } } }