/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.impl.argdelegation;
import java.util.*;
import net.java.sip.communicator.service.argdelegation.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.launchutils.*;
import org.osgi.framework.*;
/**
* Implements the <tt>UriDelegationPeer</tt> interface from our argument handler
* utility. We use this handler to relay arguments to URI handlers that have
* been registered from other services such as the SIP provider for example.
*
* @author Emil Ivov
*/
public class ArgDelegationPeerImpl
implements ArgDelegationPeer,
ServiceListener
{
/**
* The <tt>Logger</tt> used by the <tt>ArgDelegationPeerImpl</tt> class and
* its instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(ArgDelegationPeerImpl.class);
/**
* The list of uriHandlers that we are currently aware of.
*/
private final Map<String, UriHandler> uriHandlers
= new Hashtable<String, UriHandler>();
/**
* Creates an instance of this peer and scans <tt>bundleContext</tt> for all
* existing <tt>UriHandler</tt>
*
* @param bundleContext a reference to a currently valid instance of a
* bundle context.
*/
public ArgDelegationPeerImpl(BundleContext bundleContext)
{
Collection<ServiceReference<UriHandler>> uriHandlerRefs
= ServiceUtils.getServiceReferences(
bundleContext,
UriHandler.class);
if (!uriHandlerRefs.isEmpty())
{
synchronized (uriHandlers)
{
for (ServiceReference<UriHandler> uriHandlerRef
: uriHandlerRefs)
{
UriHandler uriHandler
= bundleContext.getService(uriHandlerRef);
for (String protocol : uriHandler.getProtocol())
{
uriHandlers.put(protocol, uriHandler);
}
}
}
}
}
/**
* Listens for <tt>UriHandlers</tt> that are registered in the bundle
* context after we had started so that we could add them to the list
* of currently known handlers.
*
* @param event the event containing the newly (un)registered service.
*/
public void serviceChanged(ServiceEvent event)
{
BundleContext bc
= event.getServiceReference().getBundle().getBundleContext();
/*
* TODO When the Update button of the plug-in manager is invoked for the
* IRC protocol provider plug-in, bc is of value null and thus causes a
* NullPointerException. Determine whether it is a problem (in general)
* to not process ServiceEvent.UNREGISTERING in such a case.
*/
if (bc == null)
return;
Object service = bc.getService(event.getServiceReference());
//we are only interested in UriHandler-s
if (!(service instanceof UriHandler))
return;
UriHandler uriHandler = (UriHandler) service;
synchronized (uriHandlers)
{
switch (event.getType())
{
case ServiceEvent.MODIFIED:
case ServiceEvent.REGISTERED:
for (String protocol : uriHandler.getProtocol())
{
uriHandlers.put(protocol, uriHandler);
}
break;
case ServiceEvent.UNREGISTERING:
for (String protocol : uriHandler.getProtocol())
{
if(uriHandlers.get(protocol) == uriHandler)
uriHandlers.remove(protocol);
}
break;
}
}
}
/**
* Relays <tt>uirArg</tt> to the corresponding handler or shows an error
* message in case no handler has been registered for the corresponding
* protocol.
*
* @param uriArg the uri that we've been passed and that we'd like to
* delegate to the corresponding provider.
*/
public void handleUri(String uriArg)
{
if (logger.isTraceEnabled())
logger.trace("Handling URI: " + uriArg);
//first parse the uri and determine the scheme/protocol
//the parsing is currently a bit oversimplified so we'd probably need
//to revisit it at some point.
int colonIndex = uriArg.indexOf(":");
if( colonIndex == -1)
{
//no scheme, we don't know how to handle the URI
ArgDelegationActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(
"Could not determine how to handle: " + uriArg
+ ".\nNo protocol scheme found.",
"Error handling URI",
PopupDialog.ERROR_MESSAGE);
return;
}
String scheme = uriArg.substring(0, colonIndex);
UriHandler handler;
synchronized (uriHandlers) {
handler = uriHandlers.get(scheme);
}
//if handler is null we need to tell the user.
if(handler == null)
{
if (logger.isTraceEnabled())
logger.trace("Couldn't open " + uriArg
+ "No handler found for protocol"+ scheme);
ArgDelegationActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(
"\"" + scheme + "\" URIs are currently not supported.",
"Error handling URI",
PopupDialog.ERROR_MESSAGE);
return;
}
//we're all set. let's do the handling now.
try
{
handler.handleUri(uriArg);
}
//catch every possible exception
catch(Throwable thr)
{
// ThreadDeath should always be re-thrown.
if (thr instanceof ThreadDeath)
throw (ThreadDeath) thr;
ArgDelegationActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(
"Error handling " + uriArg,
"Error handling URI",
PopupDialog.ERROR_MESSAGE);
logger.error("Failed to handle \""+ uriArg +"\"", thr);
}
}
/**
* This method would simply bring the application on focus as it is called
* when the user has tried to launch a second instance of SIP Communicator
* while a first one was already running. Future implementations may also
* show an error/information message to the user notifying them that a
* second instance is not to be launched.
*/
public void handleConcurrentInvocationRequest()
{
ArgDelegationActivator.getUIService().setVisible(true);
}
}