/** @author Symphorien Wanko */ public class PopupMessageHandlerSLick extends TestSuite implements BundleActivator { /** Logger for this class */ private static Logger logger = Logger.getLogger(PopupMessageHandlerSLick.class); /** our bundle context */ protected static BundleContext bundleContext = null; /** implements BundleActivator.start() */ public void start(BundleContext bc) throws Exception { logger.info("starting popup message test "); bundleContext = bc; setName("PopupMessageHandlerSLick"); Hashtable<String, String> properties = new Hashtable<String, String>(); properties.put("service.pid", getName()); // we maybe are running on machine without WM and systray // (test server machine), skip tests if (ServiceUtils.getService(bc, SystrayService.class) != null) { addTest(TestPopupMessageHandler.suite()); } bundleContext.registerService(getClass().getName(), this, properties); } /** implements BundleActivator.stop() */ public void stop(BundleContext bc) throws Exception {} }
/** * Bundle adds Android specific notification handlers. * * @author Pawel Domas */ public class NotificationActivator implements BundleActivator { /** The logger */ private final Logger logger = Logger.getLogger(NotificationActivator.class); /** OSGI bundle context. */ protected static BundleContext bundleContext; /** Notification service instance. */ private static NotificationService notificationService; /** Vibrate handler instance. */ private VibrateHandlerImpl vibrateHandler; /** {@inheritDoc} */ public void start(BundleContext bc) throws Exception { bundleContext = bc; try { logger.logEntry(); logger.info("Android notification handler Service...[ STARTED ]"); // Get the notification service implementation ServiceReference notifReference = bundleContext.getServiceReference(NotificationService.class.getName()); notificationService = (NotificationService) bundleContext.getService(notifReference); vibrateHandler = new VibrateHandlerImpl(); notificationService.addActionHandler(vibrateHandler); logger.info("Android notification handler Service...[REGISTERED]"); } finally { logger.logExit(); } } /** {@inheritDoc} */ public void stop(BundleContext bc) throws Exception { notificationService.removeActionHandler(vibrateHandler.getActionType()); logger.info("Android notification handler Service ...[STOPPED]"); } }
/** * Activator for the Metacafe source bundle. * * @author Purvesh Sahoo */ public class MetacafeActivator implements BundleActivator { /** The <tt>Logger</tt> used by the <tt>MetacafeActivator</tt> class. */ private static final Logger logger = Logger.getLogger(MetacafeActivator.class); /** The metacafe service registration. */ private ServiceRegistration metacafeServReg = null; /** The source implementation reference. */ private static ReplacementService metacafeSource = null; /** * Starts the Metacafe replacement source bundle * * @param context the <tt>BundleContext</tt> as provided from the OSGi framework * @throws Exception if anything goes wrong */ public void start(BundleContext context) throws Exception { Hashtable<String, String> hashtable = new Hashtable<String, String>(); hashtable.put( ReplacementService.SOURCE_NAME, ReplacementServiceMetacafeImpl.METACAFE_CONFIG_LABEL); metacafeSource = new ReplacementServiceMetacafeImpl(); metacafeServReg = context.registerService(ReplacementService.class.getName(), metacafeSource, hashtable); logger.info("Metacafe source implementation [STARTED]."); } /** * Unregisters the Metacafe replacement service. * * @param context BundleContext * @throws Exception if anything goes wrong */ public void stop(BundleContext context) throws Exception { metacafeServReg.unregister(); logger.info("Metacafe source implementation [STOPPED]."); } }
/** * The class listens for "focus joined room" and "conference created" events and adds the info about * all conference components versions to Jicofo's MUC presence. * * @author Pawel Domas */ public class VersionBroadcaster extends EventHandlerActivator { /** The logger */ private static final Logger logger = Logger.getLogger(VersionBroadcaster.class); /** <tt>FocusManager</tt> instance used to access <tt>JitsiMeetConference</tt>. */ private FocusManager focusManager; /** <tt>VersionService</tt> which provides Jicofo version. */ private VersionService versionService; /** Jitsi Meet tools used to add packet extension to Jicofo presence. */ private OperationSetJitsiMeetTools meetTools; /** Creates new instance of <tt>VersionBroadcaster</tt>. */ public VersionBroadcaster() { super(new String[] {EventFactory.FOCUS_JOINED_ROOM_TOPIC, EventFactory.CONFERENCE_ROOM_TOPIC}); } /** {@inheritDoc} */ @Override public void start(BundleContext bundleContext) throws Exception { focusManager = ServiceUtils.getService(bundleContext, FocusManager.class); Assert.notNull(focusManager, "focusManager"); versionService = ServiceUtils.getService(bundleContext, VersionService.class); Assert.notNull(versionService, "versionService"); meetTools = focusManager.getOperationSet(OperationSetJitsiMeetTools.class); Assert.notNull(meetTools, "meetTools"); super.start(bundleContext); } /** {@inheritDoc} */ @Override public void stop(BundleContext bundleContext) throws Exception { super.stop(bundleContext); focusManager = null; versionService = null; meetTools = null; } /** * Handles {@link EventFactory#FOCUS_JOINED_ROOM_TOPIC} and {@link * EventFactory#CONFERENCE_ROOM_TOPIC}. * * <p>{@inheritDoc} */ @Override public void handleEvent(Event event) { String topic = event.getTopic(); if (!topic.equals(EventFactory.FOCUS_JOINED_ROOM_TOPIC) && !topic.equals(EventFactory.CONFERENCE_ROOM_TOPIC)) { logger.error("Unexpected event topic: " + topic); return; } String roomJid = (String) event.getProperty(EventFactory.ROOM_JID_KEY); JitsiMeetConference conference = focusManager.getConference(roomJid); if (conference == null) { logger.error("Conference is null"); return; } ChatRoom chatRoom = conference.getChatRoom(); if (chatRoom == null) { logger.error("Chat room is null"); return; } JitsiMeetServices meetServices = focusManager.getJitsiMeetServices(); ComponentVersionsExtension versionsExtension = new ComponentVersionsExtension(); // XMPP Version xmppServerVersion = meetServices.getXMPPServerVersion(); if (xmppServerVersion != null) { versionsExtension.addComponentVersion( ComponentVersionsExtension.COMPONENT_XMPP_SERVER, xmppServerVersion.getNameVersionOsString()); } // Conference focus org.jitsi.service.version.Version jicofoVersion = versionService.getCurrentVersion(); versionsExtension.addComponentVersion( ComponentVersionsExtension.COMPONENT_FOCUS, jicofoVersion.getApplicationName() + "(" + jicofoVersion.toString() + "," + System.getProperty("os.name") + ")"); // Videobridge // It is not be reported for FOCUS_JOINED_ROOM_TOPIC String bridgeJid = (String) event.getProperty(EventFactory.BRIDGE_JID_KEY); Version jvbVersion = bridgeJid == null ? null : meetServices.getBridgeVersion(bridgeJid); if (jvbVersion != null) { versionsExtension.addComponentVersion( ComponentVersionsExtension.COMPONENT_VIDEOBRIDGE, jvbVersion.getNameVersionOsString()); } meetTools.sendPresenceExtension(chatRoom, versionsExtension); if (logger.isDebugEnabled()) logger.debug("Sending versions: " + versionsExtension.toXML()); } }
/** * Provides capabilities to a specific <code>JComponent</code> to contain <code>PluginComponent * </code>s, track when they are added and removed. * * @author Lyubomir Marinov */ public class PluginContainer implements PluginComponentListener { /** * The <tt>Logger</tt> used by the <tt>PluginContainer</tt> class and its instances for logging * output. */ private static final Logger logger = Logger.getLogger(PluginContainer.class); /** * The <code>JComponent</code> which contains the components of the <code>PluginComponent</code>s * managed by this instance. */ private final JComponent container; /** The container id of the <code>PluginComponent</code> managed by this instance. */ private final Container containerId; /** * The list of <code>PluginComponent</code> instances which have their components added to this * <code>PluginContainer</code>. */ private final java.util.List<PluginComponent> pluginComponents = new LinkedList<PluginComponent>(); /** * Initializes a new <code>PluginContainer</code> instance which is to provide capabilities to a * specific <code>JComponent</code> container with a specific <code>Container</code> id to contain * <code>PluginComponent</code> and track when they are added and removed. * * @param container the <code>JComponent</code> container the new instance is to provide its * capabilities to * @param containerId the <code>Container</code> id of the specified <code>container</code> */ public PluginContainer(JComponent container, Container containerId) { this.container = container; this.containerId = containerId; initPluginComponents(); } /** * Adds a specific <tt>Component</tt> to a specific <tt>JComponent</tt> container. Allows * extenders to apply custom logic to the exact placement of the specified <tt>Component</tt> in * the specified container. * * @param component the <tt>Component</tt> to be added to the specified <tt>JComponent</tt> * container * @param container the <tt>JComponent</tt> container to add the specified <tt>Component</tt> to * @param preferredIndex the index at which <tt>component</tt> is to be added to * <tt>container</tt> if possible or <tt>-1</tt> if there is no preference with respect to the * index in question */ protected void addComponentToContainer( Component component, JComponent container, int preferredIndex) { if ((0 <= preferredIndex) && (preferredIndex < getComponentCount(container))) container.add(component, preferredIndex); else container.add(component); } /** * Adds the component of a specific <tt>PluginComponent</tt> to the associated <tt>Container</tt>. * * @param c the <tt>PluginComponent</tt> which is to have its component added to the * <tt>Container</tt> associated with this <tt>PluginContainer</tt> */ private synchronized void addPluginComponent(PluginComponent c) { /* * Try to respect positionIndex of PluginComponent to some extent: * PluginComponents with positionIndex equal to 0 go at the beginning, * these with positionIndex equal to -1 follow them and then go these * with positionIndex greater than 0. */ int cIndex = c.getPositionIndex(); int index = -1; int i = 0; for (PluginComponent pluginComponent : pluginComponents) { if (pluginComponent.equals(c)) return; if (-1 == index) { int pluginComponentIndex = pluginComponent.getPositionIndex(); if ((0 == cIndex) || (-1 == cIndex)) { if ((0 != pluginComponentIndex) && (cIndex != pluginComponentIndex)) index = i; } else if (cIndex < pluginComponentIndex) index = i; } i++; } int pluginComponentCount = pluginComponents.size(); if (-1 == index) index = pluginComponents.size(); /* * The container may have added Components of its own apart from the * ones this PluginContainer has added to it. Since the common case for * the additional Components is to have them appear at the beginning, * adjust the index so it gets correct in the common case. */ int containerComponentCount = getComponentCount(container); addComponentToContainer( (Component) c.getComponent(), container, (containerComponentCount > pluginComponentCount) ? (index + (containerComponentCount - pluginComponentCount)) : index); pluginComponents.add(index, c); container.revalidate(); container.repaint(); } /** * Runs clean-up for associated resources which need explicit disposal (e.g. listeners keeping * this instance alive because they were added to the model which operationally outlives this * instance). */ public void dispose() { GuiActivator.getUIService().removePluginComponentListener(this); /* * Explicitly remove the components of the PluginComponent instances * because the latter are registered with OSGi and are thus global. */ synchronized (this) { for (PluginComponent pluginComponent : pluginComponents) container.remove((Component) pluginComponent.getComponent()); pluginComponents.clear(); } } /** * Gets the number of <tt>Component</tt>s in a specific <tt>JComponent</tt> container. For * example, returns the result of <tt>getMenuComponentCount()</tt> if <tt>container</tt> is an * instance of <tt>JMenu</tt>. * * @param container the <tt>JComponent</tt> container to get the number of <tt>Component</tt>s of * @return the number of <tt>Component</tt>s in the specified <tt>container</tt> */ protected int getComponentCount(JComponent container) { return (container instanceof JMenu) ? ((JMenu) container).getMenuComponentCount() : container.getComponentCount(); } /** * Gets the <tt>PluginComponent</tt>s of this <tt>PluginContainer</tt>. * * @return an <tt>Iterable</tt> over the <tt>PluginComponent</tt>s of this * <tt>PluginContainer</tt> */ public Iterable<PluginComponent> getPluginComponents() { return pluginComponents; } /** * Adds the <tt>Component</tt>s of the <tt>PluginComponent</tt>s registered in the OSGi * <tt>BundleContext</tt> in the associated <tt>Container</tt>. */ private void initPluginComponents() { // Look for PluginComponents registered in the OSGi BundleContext. ServiceReference[] serRefs = null; try { serRefs = GuiActivator.bundleContext.getServiceReferences( PluginComponent.class.getName(), "(" + Container.CONTAINER_ID + "=" + containerId.getID() + ")"); } catch (InvalidSyntaxException exc) { logger.error("Could not obtain plugin reference.", exc); } if (serRefs != null) { for (ServiceReference serRef : serRefs) { PluginComponent component = (PluginComponent) GuiActivator.bundleContext.getService(serRef); addPluginComponent(component); } } GuiActivator.getUIService().addPluginComponentListener(this); } /** * Implements {@link PluginComponentListener#pluginComponentAdded(PluginComponentEvent)}. * * @param event a <tt>PluginComponentEvent</tt> which specifies the <tt>PluginComponent</tt> which * has been added */ public void pluginComponentAdded(PluginComponentEvent event) { PluginComponent c = event.getPluginComponent(); if (c.getContainer().equals(containerId)) addPluginComponent(c); } /** * Implements {@link PluginComponentListener#pluginComponentRemoved(PluginComponentEvent)}. * * @param event a <tt>PluginComponentEvent</tt> which specifies the <tt>PluginComponent</tt> which * has been added */ public void pluginComponentRemoved(PluginComponentEvent event) { PluginComponent c = event.getPluginComponent(); if (c.getContainer().equals(containerId)) removePluginComponent(c); } /** * Removes the component of a specific <code>PluginComponent</code> from this <code> * PluginContainer</code>. * * @param c the <code>PluginComponent</code> which is to have its component removed from this * <code>PluginContainer</code> */ private synchronized void removePluginComponent(PluginComponent c) { container.remove((Component) c.getComponent()); pluginComponents.remove(c); } }
/** * A SIP implementation of the protocol provider factory interface. * * @author Emil Ivov */ public class ProtocolProviderFactorySipImpl extends ProtocolProviderFactory { private static final Logger logger = Logger.getLogger(ProtocolProviderFactorySipImpl.class); /** The table that we store our accounts in. */ private Hashtable registeredAccounts = new Hashtable(); /** Constructs a new instance of the ProtocolProviderFactorySipImpl. */ public ProtocolProviderFactorySipImpl() {} /** * Returns the ServiceReference for the protocol provider corresponding to the specified accountID * or null if the accountID is unknown. * * @param accountID the accountID of the protocol provider we'd like to get * @return a ServiceReference object to the protocol provider with the specified account id and * null if the account id is unknwon to the provider factory. */ public ServiceReference getProviderForAccount(AccountID accountID) { ServiceRegistration registration = (ServiceRegistration) registeredAccounts.get(accountID); return (registration == null) ? null : registration.getReference(); } /** * Returns a copy of the list containing all accounts currently registered in this protocol * provider. * * @return a copy of the llist containing all accounts currently installed in the protocol * provider. */ public ArrayList getRegisteredAccounts() { return new ArrayList(registeredAccounts.keySet()); } /** * Initializes and creates an account corresponding to the specified accountProperties and * registers the resulting ProtocolProvider in the <tt>context</tt> BundleContext parameter. * * @param userIDStr the user identifier uniquely representing the newly created account within the * protocol namespace. * @param accountProperties a set of protocol (or implementation) specific properties defining the * new account. * @return the AccountID of the newly created account. * @throws IllegalArgumentException if userID does not correspond to an identifier in the context * of the underlying protocol or if accountProperties does not contain a complete set of * account installation properties. * @throws IllegalStateException if the account has already been installed. * @throws NullPointerException if any of the arguments is null. */ public AccountID installAccount(String userIDStr, Map accountProperties) { BundleContext context = SipActivator.getBundleContext(); if (context == null) throw new NullPointerException("The specified BundleContext was null"); if (userIDStr == null) throw new NullPointerException("The specified AccountID was null"); accountProperties.put(USER_ID, userIDStr); if (accountProperties == null) throw new NullPointerException("The specified property map was null"); String serverAddress = (String) accountProperties.get(SERVER_ADDRESS); if (serverAddress == null) throw new NullPointerException("null is not a valid ServerAddress"); if (!accountProperties.containsKey(PROTOCOL)) accountProperties.put(PROTOCOL, ProtocolNames.SIP); AccountID accountID = new SipAccountID(userIDStr, accountProperties, serverAddress); // make sure we haven't seen this account id before. if (registeredAccounts.containsKey(accountID)) throw new IllegalStateException("An account for id " + userIDStr + " was already installed!"); // first store the account and only then load it as the load generates // an osgi event, the osgi event triggers (trhgough the UI) a call to // the register() method and it needs to acces the configuration service // and check for a password. this.storeAccount(SipActivator.getBundleContext(), accountID); try { accountID = loadAccount(accountProperties); } catch (RuntimeException exc) { // it might happen that load-ing the account fails because of a bad // initialization. if this is the case, make sure we remove it. this.removeStoredAccount(SipActivator.getBundleContext(), accountID); throw exc; } return accountID; } /** * Initializes and creates an account corresponding to the specified accountProperties and * registers the resulting ProtocolProvider in the <tt>context</tt> BundleContext parameter. * * @param accountProperties a set of protocol (or implementation) specific properties defining the * new account. * @return the AccountID of the newly created account */ protected AccountID loadAccount(Map accountProperties) { BundleContext context = SipActivator.getBundleContext(); if (context == null) throw new NullPointerException("The specified BundleContext was null"); String userIDStr = (String) accountProperties.get(USER_ID); if (userIDStr == null) throw new NullPointerException("The account properties contained no user id."); if (accountProperties == null) throw new NullPointerException("The specified property map was null"); String serverAddress = (String) accountProperties.get(SERVER_ADDRESS); if (serverAddress == null) throw new NullPointerException(serverAddress + " is not a valid ServerAddress"); if (!accountProperties.containsKey(PROTOCOL)) accountProperties.put(PROTOCOL, ProtocolNames.SIP); SipAccountID accountID = new SipAccountID(userIDStr, accountProperties, serverAddress); // get a reference to the configuration service and register whatever // properties we have in it. Hashtable properties = new Hashtable(); properties.put(PROTOCOL, ProtocolNames.SIP); properties.put(USER_ID, userIDStr); ProtocolProviderServiceSipImpl sipProtocolProvider = new ProtocolProviderServiceSipImpl(); try { sipProtocolProvider.initialize(userIDStr, accountID); // We store again the account in order to store all properties added // during the protocol provider initialization. this.storeAccount(SipActivator.getBundleContext(), accountID); } catch (OperationFailedException ex) { logger.error("Failed to initialize account", ex); throw new IllegalArgumentException("Failed to initialize account" + ex.getMessage()); } ServiceRegistration registration = context.registerService( ProtocolProviderService.class.getName(), sipProtocolProvider, properties); registeredAccounts.put(accountID, registration); return accountID; } /** Loads (and hence installs) all accounts previously stored in the configuration service. */ public void loadStoredAccounts() { super.loadStoredAccounts(SipActivator.getBundleContext()); } /** * Removes the specified account from the list of accounts that this provider factory is handling. * If the specified accountID is unknown to the ProtocolProviderFactory, the call has no effect * and false is returned. This method is persistent in nature and once called the account * corresponding to the specified ID will not be loaded during future runs of the project. * * @param accountID the ID of the account to remove. * @return true if an account with the specified ID existed and was removed and false otherwise. */ public boolean uninstallAccount(AccountID accountID) { // unregister the protocol provider ServiceReference serRef = getProviderForAccount(accountID); if (serRef == null) return false; ProtocolProviderService protocolProvider = (ProtocolProviderService) SipActivator.getBundleContext().getService(serRef); try { protocolProvider.unregister(); } catch (OperationFailedException e) { logger.error( "Failed to unregister protocol provider for account : " + accountID + " caused by : " + e); } ServiceRegistration registration = (ServiceRegistration) registeredAccounts.remove(accountID); if (registration == null) return false; // kill the service registration.unregister(); return removeStoredAccount(SipActivator.getBundleContext(), accountID); } /** Prepares the factory for bundle shutdown. */ public void stop() { logger.trace("Preparing to stop all SIP protocol providers."); Enumeration registrations = this.registeredAccounts.elements(); while (registrations.hasMoreElements()) { ServiceRegistration reg = ((ServiceRegistration) registrations.nextElement()); ProtocolProviderServiceSipImpl provider = (ProtocolProviderServiceSipImpl) SipActivator.getBundleContext().getService(reg.getReference()); // do an attempt to kill the provider provider.shutdown(); reg.unregister(); } registeredAccounts.clear(); } /** * Saves the password for the specified account after scrambling it a bit so that it is not * visible from first sight (Method remains highly insecure). * * @param accountID the AccountID for the account whose password we're storing. * @param passwd the password itself. * @throws java.lang.IllegalArgumentException if no account corresponding to <tt>accountID</tt> * has been previously stored. */ public void storePassword(AccountID accountID, String passwd) throws IllegalArgumentException { super.storePassword(SipActivator.getBundleContext(), accountID, passwd); } /** * Returns the password last saved for the specified account. * * @param accountID the AccountID for the account whose password we're looking for.. * @return a String containing the password for the specified accountID. * @throws java.lang.IllegalArgumentException if no account corresponding to <tt>accountID</tt> * has been previously stored. */ public String loadPassword(AccountID accountID) throws IllegalArgumentException { return super.loadPassword(SipActivator.getBundleContext(), accountID); } }
/** * Implements {@link BundleActivator} for the <tt>msofficecomm</tt> bundle. * * @author Lyubomir Marinov */ public class MsOfficeCommActivator implements BundleActivator { /** * The <tt>Logger</tt> used by the <tt>MsOfficeCommActivator</tt> class and its instances for * logging output. */ private static final Logger logger = Logger.getLogger(MsOfficeCommActivator.class); /** * Starts the <tt>msofficecomm</tt> bundle in a specific {@link BundleContext}. * * @param bundleContext the <tt>BundleContext</tt> in which the <tt>msofficecomm</tt> bundle is to * be started * @throws Exception if anything goes wrong while starting the <tt>msofficecomm</tt> bundle in the * specified <tt>BundleContext</tt> */ public void start(BundleContext bundleContext) throws Exception { // The msofficecomm bundle is available on Windows only. if (!OSUtils.IS_WINDOWS) return; if (logger.isInfoEnabled()) logger.info("MsOfficeComm plugin ... [STARTED]"); Messenger.start(bundleContext); boolean stopMessenger = true; try { int hresult = OutOfProcessServer.start(); if (logger.isInfoEnabled()) logger.info("MsOfficeComm started OutOfProcessServer HRESULT:" + hresult); if (hresult < 0) throw new RuntimeException("HRESULT " + hresult); else stopMessenger = false; } finally { if (stopMessenger) Messenger.stop(bundleContext); } } /** * Stops the <tt>msofficecomm</tt> bundle in a specific {@link BundleContext}. * * @param bundleContext the <tt>BundleContext</tt> in which the <tt>msofficecomm</tt> bundle is to * be stopped * @throws Exception if anything goes wrong while stopping the <tt>msofficecomm</tt> bundle in the * specified <tt>BundleContext</tt> */ public void stop(BundleContext bundleContext) throws Exception { // The msofficecomm bundle is available on Windows only. if (!OSUtils.IS_WINDOWS) return; try { int hresult = OutOfProcessServer.stop(); if (hresult < 0) throw new RuntimeException("HRESULT " + hresult); } finally { Messenger.stop(bundleContext); } if (logger.isInfoEnabled()) logger.info("MsOfficeComm plugin ... [UNREGISTERED]"); } }
/** * Represents the Gibberish protocol icon. Implements the <tt>ProtocolIcon</tt> interface in order * to provide a gibberish logo image in two different sizes. * * @author Yana Stamcheva */ public class ProtocolIconGibberishImpl implements ProtocolIcon { private static Logger logger = Logger.getLogger(ProtocolIconGibberishImpl.class); private static ResourceManagementService resourcesService; /** A hash table containing the protocol icon in different sizes. */ private static Hashtable<String, byte[]> iconsTable = new Hashtable<String, byte[]>(); static { iconsTable.put( ProtocolIcon.ICON_SIZE_16x16, getImageInBytes("service.protocol.gibberish.GIBBERISH_16x16")); iconsTable.put( ProtocolIcon.ICON_SIZE_32x32, getImageInBytes("service.protocol.gibberish.GIBBERISH_32x32")); iconsTable.put( ProtocolIcon.ICON_SIZE_48x48, getImageInBytes("service.protocol.gibberish.GIBBERISH_48x48")); iconsTable.put( ProtocolIcon.ICON_SIZE_64x64, getImageInBytes("service.protocol.gibberish.GIBBERISH_64x64")); } /** A hash table containing the path to the protocol icon in different sizes. */ private static Hashtable<String, String> iconPathsTable = new Hashtable<String, String>(); static { iconPathsTable.put( ProtocolIcon.ICON_SIZE_16x16, getResources().getImagePath("service.protocol.gibberish.GIBBERISH_16x16")); iconPathsTable.put( ProtocolIcon.ICON_SIZE_32x32, getResources().getImagePath("service.protocol.gibberish.GIBBERISH_32x32")); iconPathsTable.put( ProtocolIcon.ICON_SIZE_48x48, getResources().getImagePath("service.protocol.gibberish.GIBBERISH_48x48")); iconPathsTable.put( ProtocolIcon.ICON_SIZE_64x64, getResources().getImagePath("service.protocol.gibberish.GIBBERISH_64x64")); } /** * Implements the <tt>ProtocolIcon.getSupportedSizes()</tt> method. Returns an iterator to a set * containing the supported icon sizes. * * @return an iterator to a set containing the supported icon sizes */ public Iterator<String> getSupportedSizes() { return iconsTable.keySet().iterator(); } /** Returne TRUE if a icon with the given size is supported, FALSE-otherwise. */ public boolean isSizeSupported(String iconSize) { return iconsTable.containsKey(iconSize); } /** * Returns the icon image in the given size. * * @param iconSize the icon size; one of ICON_SIZE_XXX constants */ public byte[] getIcon(String iconSize) { return iconsTable.get(iconSize); } /** * Returns a path to the icon with the given size. * * @param iconSize the size of the icon we're looking for * @return the path to the icon with the given size */ public String getIconPath(String iconSize) { return iconPathsTable.get(iconSize); } /** * Returns the icon image used to represent the protocol connecting state. * * @return the icon image used to represent the protocol connecting state */ public byte[] getConnectingIcon() { return getImageInBytes("gibberishOnlineIcon"); } /** * Returns the byte representation of the image corresponding to the given identifier. * * @param imageID the identifier of the image * @return the byte representation of the image corresponding to the given identifier. */ private static byte[] getImageInBytes(String imageID) { InputStream in = getResources().getImageInputStream(imageID); if (in == null) return null; byte[] image = null; try { image = new byte[in.available()]; in.read(image); } catch (IOException e) { logger.error("Failed to load image:" + imageID, e); } return image; } public static ResourceManagementService getResources() { if (resourcesService == null) { ServiceReference serviceReference = GibberishActivator.bundleContext.getServiceReference( ResourceManagementService.class.getName()); if (serviceReference == null) return null; resourcesService = (ResourceManagementService) GibberishActivator.bundleContext.getService(serviceReference); } return resourcesService; } }
/** * The <tt>GibberishAccountRegistrationWizard</tt> is an implementation of the * <tt>AccountRegistrationWizard</tt> for the Gibberish protocol. It allows the user to create and * configure a new Gibberish account. * * @author Emil Ivov */ public class GibberishAccountRegistrationWizard extends DesktopAccountRegistrationWizard { private final Logger logger = Logger.getLogger(GibberishAccountRegistrationWizard.class); /** The first page of the gibberish account registration wizard. */ private FirstWizardPage firstWizardPage; /** The object that we use to store details on an account that we will be creating. */ private GibberishAccountRegistration registration = new GibberishAccountRegistration(); private ProtocolProviderService protocolProvider; /** * Creates an instance of <tt>GibberishAccountRegistrationWizard</tt>. * * @param wizardContainer the wizard container, where this wizard is added */ public GibberishAccountRegistrationWizard(WizardContainer wizardContainer) { setWizardContainer(wizardContainer); wizardContainer.setFinishButtonText(Resources.getString("service.gui.SIGN_IN")); } /** * Implements the <code>AccountRegistrationWizard.getIcon</code> method. Returns the icon to be * used for this wizard. * * @return byte[] */ public byte[] getIcon() { return Resources.getImage(Resources.GIBBERISH_LOGO); } /** * Implements the <code>AccountRegistrationWizard.getPageImage</code> method. Returns the image * used to decorate the wizard page * * @return byte[] the image used to decorate the wizard page */ public byte[] getPageImage() { return Resources.getImage(Resources.PAGE_IMAGE); } /** * Implements the <code>AccountRegistrationWizard.getProtocolName</code> method. Returns the * protocol name for this wizard. * * @return String */ public String getProtocolName() { return Resources.getString("plugin.gibberishaccregwizz.PROTOCOL_NAME"); } /** * Implements the <code>AccountRegistrationWizard.getProtocolDescription * </code> method. Returns the description of the protocol for this wizard. * * @return String */ public String getProtocolDescription() { return Resources.getString("plugin.gibberishaccregwizz.PROTOCOL_DESCRIPTION"); } /** * Returns the set of pages contained in this wizard. * * @return Iterator */ public Iterator<WizardPage> getPages() { java.util.List<WizardPage> pages = new ArrayList<WizardPage>(); firstWizardPage = new FirstWizardPage(this); pages.add(firstWizardPage); return pages.iterator(); } /** * Returns the set of data that user has entered through this wizard. * * @return Iterator */ public Iterator<Map.Entry<String, String>> getSummary() { Map<String, String> summaryTable = new Hashtable<String, String>(); summaryTable.put("User ID", registration.getUserID()); return summaryTable.entrySet().iterator(); } /** * Defines the operations that will be executed when the user clicks on the wizard "Signin" * button. * * @return the created <tt>ProtocolProviderService</tt> corresponding to the new account * @throws OperationFailedException if the operation didn't succeed */ public ProtocolProviderService signin() throws OperationFailedException { firstWizardPage.commitPage(); return signin(registration.getUserID(), null); } /** * Defines the operations that will be executed when the user clicks on the wizard "Signin" * button. * * @param userName the user name to sign in with * @param password the password to sign in with * @return the created <tt>ProtocolProviderService</tt> corresponding to the new account * @throws OperationFailedException if the operation didn't succeed */ public ProtocolProviderService signin(String userName, String password) throws OperationFailedException { ProtocolProviderFactory factory = GibberishAccRegWizzActivator.getGibberishProtocolProviderFactory(); return this.installAccount(factory, userName); } /** * Creates an account for the given user and password. * * @param providerFactory the ProtocolProviderFactory which will create the account * @param user the user identifier * @return the <tt>ProtocolProviderService</tt> for the new account. */ public ProtocolProviderService installAccount( ProtocolProviderFactory providerFactory, String user) throws OperationFailedException { Hashtable<String, String> accountProperties = new Hashtable<String, String>(); accountProperties.put( ProtocolProviderFactory.ACCOUNT_ICON_PATH, "resources/images/protocol/gibberish/gibberish32x32.png"); if (registration.isRememberPassword()) { accountProperties.put(ProtocolProviderFactory.PASSWORD, registration.getPassword()); } if (isModification()) { providerFactory.uninstallAccount(protocolProvider.getAccountID()); this.protocolProvider = null; setModification(false); } try { AccountID accountID = providerFactory.installAccount(user, accountProperties); ServiceReference serRef = providerFactory.getProviderForAccount(accountID); protocolProvider = (ProtocolProviderService) GibberishAccRegWizzActivator.bundleContext.getService(serRef); } catch (IllegalStateException exc) { logger.warn(exc.getMessage()); throw new OperationFailedException( "Account already exists.", OperationFailedException.IDENTIFICATION_CONFLICT); } catch (Exception exc) { logger.warn(exc.getMessage()); throw new OperationFailedException( "Failed to add account", OperationFailedException.GENERAL_ERROR); } return protocolProvider; } /** * Fills the UserID and Password fields in this panel with the data comming from the given * protocolProvider. * * @param protocolProvider The <tt>ProtocolProviderService</tt> to load the data from. */ public void loadAccount(ProtocolProviderService protocolProvider) { setModification(true); this.protocolProvider = protocolProvider; this.registration = new GibberishAccountRegistration(); this.firstWizardPage.loadAccount(protocolProvider); } /** * Returns the registration object, which will store all the data through the wizard. * * @return the registration object, which will store all the data through the wizard */ public GibberishAccountRegistration getRegistration() { return registration; } /** * Returns the size of this wizard. * * @return the size of this wizard */ public Dimension getSize() { return new Dimension(600, 500); } /** * Returns the identifier of the page to show first in the wizard. * * @return the identifier of the page to show first in the wizard. */ public Object getFirstPageIdentifier() { return firstWizardPage.getIdentifier(); } /** * Returns the identifier of the page to show last in the wizard. * * @return the identifier of the page to show last in the wizard. */ public Object getLastPageIdentifier() { return firstWizardPage.getIdentifier(); } /** * Returns an example string, which should indicate to the user how the user name should look * like. * * @return an example string, which should indicate to the user how the user name should look * like. */ public String getUserNameExample() { return FirstWizardPage.USER_NAME_EXAMPLE; } /** * Indicates whether this wizard enables the simple "sign in" form shown when the user opens the * application for the first time. The simple "sign in" form allows user to configure her account * in one click, just specifying her username and password and leaving any other configuration as * by default. * * @return <code>true</code> if the simple "Sign in" form is enabled or <code>false</code> * otherwise. */ public boolean isSimpleFormEnabled() { return false; } /** * Returns a simple account registration form that would be the first form shown to the user. Only * if the user needs more settings she'll choose to open the advanced wizard, consisted by all * pages. * * @param isCreateAccount indicates if the simple form should be opened as a create account form * or as a login form * @return a simple account registration form */ public Object getSimpleForm(boolean isCreateAccount) { firstWizardPage = new FirstWizardPage(this); return firstWizardPage.getSimpleForm(); } }
/** * A default implementation of the <tt>ResourceManagementService</tt>. * * @author Damian Minkov * @author Yana Stamcheva * @author Lubomir Marinov * @author Adam Netocny */ public class ResourceManagementServiceImpl extends AbstractResourcesService { /** * The <tt>Logger</tt> used by the <tt>ResourceManagementServiceImpl</tt> class and its instances * for logging output. */ private static final Logger logger = Logger.getLogger(ResourceManagementServiceImpl.class); /** UI Service reference. */ private UIService uiService = null; /** Initializes already registered default resource packs. */ ResourceManagementServiceImpl() { super(ResourceManagementActivator.bundleContext); UIService serv = getUIService(); if (serv != null) { serv.repaintUI(); } } /** * Returns the <tt>UIService</tt> obtained from the bundle context. * * @return the <tt>UIService</tt> obtained from the bundle context */ private UIService getUIService() { if (uiService == null) { uiService = ServiceUtils.getService(ResourceManagementActivator.bundleContext, UIService.class); } return uiService; } /** * Gets a reference to the <tt>UIService</tt> when this one is registered. * * @param event the <tt>ServiceEvent</tt> that has notified us */ @Override public void serviceChanged(ServiceEvent event) { super.serviceChanged(event); Object sService = ResourceManagementActivator.bundleContext.getService(event.getServiceReference()); if (sService instanceof UIService && uiService == null && event.getType() == ServiceEvent.REGISTERED) { uiService = (UIService) sService; uiService.repaintUI(); } else if (sService instanceof UIService && event.getType() == ServiceEvent.UNREGISTERING) { if (uiService != null && uiService.equals(sService)) { uiService = null; } } } /** Repaints the whole UI when a skin pack has changed. */ @Override protected void onSkinPackChanged() { UIService serv = getUIService(); if (serv != null) { serv.repaintUI(); } } /** * Returns the int representation of the color corresponding to the given key. * * @param key The key of the color in the colors properties file. * @return the int representation of the color corresponding to the given key. */ public int getColor(String key) { String res = getColorResources().get(key); if (res == null) { logger.error("Missing color resource for key: " + key); return 0xFFFFFF; } else return Integer.parseInt(res, 16); } /** * Returns the string representation of the color corresponding to the given key. * * @param key The key of the color in the colors properties file. * @return the string representation of the color corresponding to the given key. */ public String getColorString(String key) { String res = getColorResources().get(key); if (res == null) { logger.error("Missing color resource for key: " + key); return "0xFFFFFF"; } else return res; } /** * Returns the <tt>InputStream</tt> of the image corresponding to the given path. * * @param path The path to the image file. * @return the <tt>InputStream</tt> of the image corresponding to the given path. */ public InputStream getImageInputStreamForPath(String path) { SkinPack skinPack = getSkinPack(); if (skinPack != null) { if (skinPack.getClass().getClassLoader().getResourceAsStream(path) != null) { return skinPack.getClass().getClassLoader().getResourceAsStream(path); } } ImagePack imagePack = getImagePack(); if (path != null && imagePack != null) return imagePack.getClass().getClassLoader().getResourceAsStream(path); return null; } /** * Returns the <tt>InputStream</tt> of the image corresponding to the given key. * * @param streamKey The identifier of the image in the resource properties file. * @return the <tt>InputStream</tt> of the image corresponding to the given key. */ public InputStream getImageInputStream(String streamKey) { String path = getImagePath(streamKey); if (path == null || path.length() == 0) { logger.warn("Missing resource for key: " + streamKey); return null; } return getImageInputStreamForPath(path); } /** * Returns the <tt>URL</tt> of the image corresponding to the given key. * * @param urlKey The identifier of the image in the resource properties file. * @return the <tt>URL</tt> of the image corresponding to the given key */ public URL getImageURL(String urlKey) { String path = getImagePath(urlKey); if (path == null || path.length() == 0) { if (logger.isInfoEnabled()) logger.info("Missing resource for key: " + urlKey); return null; } return getImageURLForPath(path); } /** * Returns the <tt>URL</tt> of the image corresponding to the given path. * * @param path The path to the given image file. * @return the <tt>URL</tt> of the image corresponding to the given path. */ public URL getImageURLForPath(String path) { SkinPack skinPack = getSkinPack(); if (skinPack != null) { if (skinPack.getClass().getClassLoader().getResource(path) != null) { return skinPack.getClass().getClassLoader().getResource(path); } } ImagePack imagePack = getImagePack(); return imagePack.getClass().getClassLoader().getResource(path); } /** * Returns the <tt>URL</tt> of the sound corresponding to the given property key. * * @return the <tt>URL</tt> of the sound corresponding to the given property key. */ public URL getSoundURL(String urlKey) { String path = getSoundPath(urlKey); if (path == null || path.length() == 0) { logger.warn("Missing resource for key: " + urlKey); return null; } return getSoundURLForPath(path); } /** * Returns the <tt>URL</tt> of the sound corresponding to the given path. * * @param path the path, for which we're looking for a sound URL * @return the <tt>URL</tt> of the sound corresponding to the given path. */ public URL getSoundURLForPath(String path) { return getSoundPack().getClass().getClassLoader().getResource(path); } /** * Loads an image from a given image identifier. * * @param imageID The identifier of the image. * @return The image for the given identifier. */ @Override public byte[] getImageInBytes(String imageID) { InputStream in = getImageInputStream(imageID); if (in == null) return null; byte[] image = null; try { image = new byte[in.available()]; in.read(image); } catch (IOException e) { logger.error("Failed to load image:" + imageID, e); } return image; } /** * Loads an image from a given image identifier. * * @param imageID The identifier of the image. * @return The image for the given identifier. */ @Override public ImageIcon getImage(String imageID) { URL imageURL = getImageURL(imageID); return (imageURL == null) ? null : new ImageIcon(imageURL); } /** * Builds a new skin bundle from the zip file content. * * @param zipFile Zip file with skin information. * @return <tt>File</tt> for the bundle. * @throws Exception When something goes wrong. */ public File prepareSkinBundleFromZip(File zipFile) throws Exception { return SkinJarBuilder.createBundleFromZip(zipFile, getImagePack()); } /** * Gets the specified setting from the config service if present, otherwise from the embedded * resources (resources/config/defaults.properties). * * @param key The setting to lookup. * @return The setting for the key or {@code null} if not found. */ @Override public String getSettingsString(String key) { Object configValue = ResourceManagementActivator.getConfigService().getProperty(key); if (configValue == null) { configValue = super.getSettingsString(key); } return configValue == null ? null : configValue.toString(); } }
/** * @author Lyubomir Marinov * @author Pawel Domas */ public class BundleImpl implements Bundle { /** The Logger */ private Logger logger = Logger.getLogger(BundleImpl.class.getName()); private BundleActivator bundleActivator; private BundleContext bundleContext; private final long bundleId; private BundleStartLevel bundleStartLevel; private final FrameworkImpl framework; private final String location; private int state = INSTALLED; public BundleImpl(FrameworkImpl framework, long bundleId, String location) { this.framework = framework; this.bundleId = bundleId; this.location = location; } public <A> A adapt(Class<A> type) { Object adapt; if (BundleStartLevel.class.equals(type)) { if (getBundleId() == 0) adapt = null; else synchronized (this) { if (bundleStartLevel == null) bundleStartLevel = new BundleStartLevelImpl(this); adapt = bundleStartLevel; } } else adapt = null; @SuppressWarnings("unchecked") A a = (A) adapt; return a; } public int compareTo(Bundle other) { long thisBundleId = getBundleId(); long otherBundleId = other.getBundleId(); if (thisBundleId < otherBundleId) return -1; else if (thisBundleId == otherBundleId) return 0; else return 1; } public Enumeration<URL> findEntries(String path, String filePattern, boolean recurse) { // TODO Auto-generated method stub return null; } public BundleContext getBundleContext() { switch (getState()) { case STARTING: case ACTIVE: case STOPPING: return bundleContext; default: return null; } } public long getBundleId() { return bundleId; } public File getDataFile(String filename) { // TODO Auto-generated method stub return null; } public URL getEntry(String path) { // TODO Auto-generated method stub return null; } public Enumeration<String> getEntryPaths(String path) { // TODO Auto-generated method stub return null; } public FrameworkImpl getFramework() { return framework; } public Dictionary<String, String> getHeaders() { return getHeaders(null); } public Dictionary<String, String> getHeaders(String locale) { // TODO Auto-generated method stub return null; } public long getLastModified() { // TODO Auto-generated method stub return 0; } public String getLocation() { return (getBundleId() == 0) ? Constants.SYSTEM_BUNDLE_LOCATION : location; } public ServiceReference<?>[] getRegisteredServices() { return framework.getRegisteredServices(); } public URL getResource(String name) { // TODO Auto-generated method stub return null; } public Enumeration<URL> getResources(String name) throws IOException { // TODO Auto-generated method stub return null; } public ServiceReference<?>[] getServicesInUse() { // TODO Auto-generated method stub return null; } public Map<X509Certificate, List<X509Certificate>> getSignerCertificates(int signersType) { // TODO Auto-generated method stub return null; } public int getState() { return state; } public String getSymbolicName() { // TODO Auto-generated method stub return null; } public Version getVersion() { // TODO Auto-generated method stub return null; } public boolean hasPermission(Object permission) { // TODO Auto-generated method stub return false; } public Class<?> loadClass(String name) throws ClassNotFoundException { return Class.forName(name); } protected void setBundleContext(BundleContext bundleContext) { this.bundleContext = bundleContext; } protected void setState(int state) { int oldState = getState(); if (oldState != state) { this.state = state; int newState = getState(); if (oldState != newState) stateChanged(oldState, newState); } } public void start() throws BundleException { start(0); } public void start(int options) throws BundleException { if (getState() == UNINSTALLED) throw new IllegalStateException("Bundle.UNINSTALLED"); BundleStartLevel bundleStartLevel = adapt(BundleStartLevel.class); FrameworkStartLevel frameworkStartLevel = getFramework().adapt(FrameworkStartLevel.class); if ((bundleStartLevel != null) && (bundleStartLevel.getStartLevel() > frameworkStartLevel.getStartLevel())) { if ((options & START_TRANSIENT) == START_TRANSIENT) throw new BundleException("startLevel"); else return; } if (getState() == ACTIVE) return; if (getState() == INSTALLED) setState(RESOLVED); setState(STARTING); String location = getLocation(); if (location != null) { BundleActivator bundleActivator = null; Throwable exception = null; try { bundleActivator = (BundleActivator) loadClass(location.replace('/', '.')).newInstance(); bundleActivator.start(getBundleContext()); } catch (Throwable t) { logger.log(Level.SEVERE, "Error starting bundle: " + bundleActivator, t); if (t instanceof ThreadDeath) throw (ThreadDeath) t; else exception = t; } if (exception == null) this.bundleActivator = bundleActivator; else { setState(STOPPING); setState(RESOLVED); getFramework().fireBundleEvent(BundleEvent.STOPPED, this); throw new BundleException("BundleActivator.start", exception); } } if (getState() == UNINSTALLED) throw new IllegalStateException("Bundle.UNINSTALLED"); setState(ACTIVE); } protected void stateChanged(int oldState, int newState) { switch (newState) { case ACTIVE: getFramework().fireBundleEvent(BundleEvent.STARTED, this); break; case RESOLVED: setBundleContext(null); break; case STARTING: setBundleContext(new BundleContextImpl(getFramework(), this)); /* * BundleEvent.STARTING is only delivered to * SynchronousBundleListeners, it is not delivered to * BundleListeners. */ break; case STOPPING: /* * BundleEvent.STOPPING is only delivered to * SynchronousBundleListeners, it is not delivered to * BundleListeners. */ break; } } public void stop() throws BundleException { stop(0); } public void stop(int options) throws BundleException { boolean wasActive = false; switch (getState()) { case ACTIVE: wasActive = true; case STARTING: setState(STOPPING); Throwable exception = null; if (wasActive && (bundleActivator != null)) { try { bundleActivator.stop(getBundleContext()); } catch (Throwable t) { if (t instanceof ThreadDeath) throw (ThreadDeath) t; else exception = t; } this.bundleActivator = null; } if (getState() == UNINSTALLED) throw new BundleException("Bundle.UNINSTALLED"); setState(RESOLVED); getFramework().fireBundleEvent(BundleEvent.STOPPED, this); if (exception != null) throw new BundleException("BundleActivator.stop", exception); break; case UNINSTALLED: throw new IllegalStateException("Bundle.UNINSTALLED"); default: break; } } public void uninstall() throws BundleException { // TODO Auto-generated method stub } public void update() throws BundleException { update(null); } public void update(InputStream input) throws BundleException { // TODO Auto-generated method stub } }
/** * Implements <tt>BundleActivator</tt> for the neomedia bundle. * * @author Martin Andre * @author Emil Ivov * @author Lyubomir Marinov * @author Boris Grozev */ public class NeomediaActivator implements BundleActivator { /** * The <tt>Logger</tt> used by the <tt>NeomediaActivator</tt> class and its instances for logging * output. */ private final Logger logger = Logger.getLogger(NeomediaActivator.class); /** Indicates if the audio configuration form should be disabled, i.e. not visible to the user. */ private static final String AUDIO_CONFIG_DISABLED_PROP = "net.java.sip.communicator.impl.neomedia.AUDIO_CONFIG_DISABLED"; /** Indicates if the video configuration form should be disabled, i.e. not visible to the user. */ private static final String VIDEO_CONFIG_DISABLED_PROP = "net.java.sip.communicator.impl.neomedia.VIDEO_CONFIG_DISABLED"; /** Indicates if the H.264 configuration form should be disabled, i.e. not visible to the user. */ private static final String H264_CONFIG_DISABLED_PROP = "net.java.sip.communicator.impl.neomedia.h264config.DISABLED"; /** Indicates if the ZRTP configuration form should be disabled, i.e. not visible to the user. */ private static final String ZRTP_CONFIG_DISABLED_PROP = "net.java.sip.communicator.impl.neomedia.zrtpconfig.DISABLED"; /** * Indicates if the call recording config form should be disabled, i.e. not visible to the user. */ private static final String CALL_RECORDING_CONFIG_DISABLED_PROP = "net.java.sip.communicator.impl.neomedia.callrecordingconfig.DISABLED"; /** * The name of the notification pop-up event displayed when the device configration has changed. */ private static final String DEVICE_CONFIGURATION_HAS_CHANGED = "DeviceConfigurationChanged"; /** * The context in which the one and only <tt>NeomediaActivator</tt> instance has started * executing. */ private static BundleContext bundleContext; /** * The <tt>ConfigurationService</tt> registered in {@link #bundleContext} and used by the * <tt>NeomediaActivator</tt> instance to read and write configuration properties. */ private static ConfigurationService configurationService; /** * The <tt>FileAccessService</tt> registered in {@link #bundleContext} and used by the * <tt>NeomediaActivator</tt> instance to safely access files. */ private static FileAccessService fileAccessService; /** The notifcation service to pop-up messages. */ private static NotificationService notificationService; /** * The one and only <tt>MediaServiceImpl</tt> instance registered in {@link #bundleContext} by the * <tt>NeomediaActivator</tt> instance. */ private static MediaServiceImpl mediaServiceImpl; /** * The <tt>ResourceManagementService</tt> registered in {@link #bundleContext} and representing * the resources such as internationalized and localized text and images used by the neomedia * bundle. */ private static ResourceManagementService resources; /** * The OSGi <tt>PacketLoggingService</tt> of {@link #mediaServiceImpl} in {@link #bundleContext} * and used for debugging. */ private static PacketLoggingService packetLoggingService = null; /** A listener to the click on the popup message concerning device configuration changes. */ private AudioDeviceConfigurationListener deviceConfigurationPropertyChangeListener; /** A {@link MediaConfigurationService} instance. */ // private static MediaConfigurationImpl mediaConfiguration; /** The audio configuration form used to define the capture/notify/playback audio devices. */ private static ConfigurationForm audioConfigurationForm; /** * Starts the execution of the neomedia bundle in the specified context. * * @param bundleContext the context in which the neomedia bundle is to start executing * @throws Exception if an error occurs while starting the execution of the neomedia bundle in the * specified context */ public void start(BundleContext bundleContext) throws Exception { if (logger.isDebugEnabled()) logger.debug("Started."); NeomediaActivator.bundleContext = bundleContext; // MediaService mediaServiceImpl = (MediaServiceImpl) LibJitsi.getMediaService(); bundleContext.registerService(MediaService.class.getName(), mediaServiceImpl, null); if (logger.isDebugEnabled()) logger.debug("Media Service ... [REGISTERED]"); // mediaConfiguration = new MediaConfigurationImpl(); // bundleContext.registerService( // MediaConfigurationService.class.getStatus(), // getMediaConfiguration(), // null); if (logger.isDebugEnabled()) logger.debug("Media Configuration ... [REGISTERED]"); ConfigurationService cfg = NeomediaActivator.getConfigurationService(); Dictionary<String, String> mediaProps = new Hashtable<String, String>(); mediaProps.put(ConfigurationForm.FORM_TYPE, ConfigurationForm.GENERAL_TYPE); // If the audio configuration form is disabled don't register it. // if ((cfg == null) || !cfg.getBoolean(AUDIO_CONFIG_DISABLED_PROP, false)) // { // audioConfigurationForm // = new LazyConfigurationForm( // AudioConfigurationPanel.class.getStatus(), // getClass().getClassLoader(), // "plugin.mediaconfig.AUDIO_ICON", // "impl.neomedia.configform.AUDIO", // 3); // // bundleContext.registerService( // ConfigurationForm.class.getStatus(), // audioConfigurationForm, // mediaProps); // // if (deviceConfigurationPropertyChangeListener == null) // { // // Initializes and registers the changed device configuration // // event ot the notification service. // getNotificationService(); // // deviceConfigurationPropertyChangeListener // = new AudioDeviceConfigurationListener(); // mediaServiceImpl // .getDeviceConfiguration() // .addPropertyChangeListener( // deviceConfigurationPropertyChangeListener); // } // } // If the video configuration form is disabled don't register it. // if ((cfg == null) || !cfg.getBoolean(VIDEO_CONFIG_DISABLED_PROP, false)) // { // bundleContext.registerService( // ConfigurationForm.class.getStatus(), // new LazyConfigurationForm( // VideoConfigurationPanel.class.getStatus(), // getClass().getClassLoader(), // "plugin.mediaconfig.VIDEO_ICON", // "impl.neomedia.configform.VIDEO", // 4), // mediaProps); // } // H.264 // If the H.264 configuration form is disabled don't register it. // if ((cfg == null) || !cfg.getBoolean(H264_CONFIG_DISABLED_PROP, false)) // { // Dictionary<String, String> h264Props // = new Hashtable<String, String>(); // // h264Props.put( // ConfigurationForm.FORM_TYPE, // ConfigurationForm.ADVANCED_TYPE); // bundleContext.registerService( // ConfigurationForm.class.getStatus(), // new LazyConfigurationForm( // ConfigurationPanel.class.getStatus(), // getClass().getClassLoader(), // "plugin.mediaconfig.VIDEO_ICON", // "impl.neomedia.configform.H264", // -1, // true), // h264Props); // } // ZRTP // If the ZRTP configuration form is disabled don't register it. // if ((cfg == null) || !cfg.getBoolean(ZRTP_CONFIG_DISABLED_PROP, false)) // { // Dictionary<String, String> securityProps // = new Hashtable<String, String>(); // // securityProps.put( ConfigurationForm.FORM_TYPE, // ConfigurationForm.SECURITY_TYPE); // bundleContext.registerService( // ConfigurationForm.class.getStatus(), // new LazyConfigurationForm( // SecurityConfigForm.class.getStatus(), // getClass().getClassLoader(), // "impl.media.security.zrtp.CONF_ICON", // "impl.media.security.zrtp.TITLE", // 0), // securityProps); // } // we use the nist-sdp stack to make parse sdp and we need to set the // following property to make sure that it would accept java generated // IPv6 addresses that contain address scope zones. System.setProperty("gov.nist.core.STRIP_ADDR_SCOPES", "true"); // AudioNotifierService AudioNotifierService audioNotifierService = LibJitsi.getAudioNotifierService(); audioNotifierService.setMute( (cfg == null) || !cfg.getBoolean("net.java.sip.communicator" + ".impl.sound.isSoundEnabled", true)); bundleContext.registerService(AudioNotifierService.class.getName(), audioNotifierService, null); if (logger.isInfoEnabled()) logger.info("Audio Notifier Service ...[REGISTERED]"); // Call Recording // If the call recording configuration form is disabled don't continue. // if ((cfg == null) // || !cfg.getBoolean(CALL_RECORDING_CONFIG_DISABLED_PROP, false)) // { // Dictionary<String, String> callRecordingProps // = new Hashtable<String, String>(); // // callRecordingProps.put( // ConfigurationForm.FORM_TYPE, // ConfigurationForm.ADVANCED_TYPE); // bundleContext.registerService( // ConfigurationForm.class.getStatus(), // new LazyConfigurationForm( // CallRecordingConfigForm.class.getStatus(), // getClass().getClassLoader(), // null, // "plugin.callrecordingconfig.CALL_RECORDING_CONFIG", // 1100, // true), // callRecordingProps); // } } /** * Stops the execution of the neomedia bundle in the specified context. * * @param bundleContext the context in which the neomedia bundle is to stop executing * @throws Exception if an error occurs while stopping the execution of the neomedia bundle in the * specified context */ public void stop(BundleContext bundleContext) throws Exception { try { if (deviceConfigurationPropertyChangeListener != null) { mediaServiceImpl .getDeviceConfiguration() .removePropertyChangeListener(deviceConfigurationPropertyChangeListener); if (deviceConfigurationPropertyChangeListener != null) { deviceConfigurationPropertyChangeListener.managePopupMessageListenerRegistration(false); deviceConfigurationPropertyChangeListener = null; } } } finally { configurationService = null; fileAccessService = null; mediaServiceImpl = null; resources = null; } } /** * Returns a reference to a ConfigurationService implementation currently registered in the bundle * context or null if no such implementation was found. * * @return a currently valid implementation of the ConfigurationService. */ public static ConfigurationService getConfigurationService() { if (configurationService == null) { configurationService = ServiceUtils.getService(bundleContext, ConfigurationService.class); } return configurationService; } /** * Returns a reference to a FileAccessService implementation currently registered in the bundle * context or null if no such implementation was found. * * @return a currently valid implementation of the FileAccessService . */ public static FileAccessService getFileAccessService() { if (fileAccessService == null) { fileAccessService = ServiceUtils.getService(bundleContext, FileAccessService.class); } return fileAccessService; } /** * Gets the <tt>MediaService</tt> implementation instance registered by the neomedia bundle. * * @return the <tt>MediaService</tt> implementation instance registered by the neomedia bundle */ public static MediaServiceImpl getMediaServiceImpl() { return mediaServiceImpl; } // public static MediaConfigurationService getMediaConfiguration() // { // return mediaConfiguration; // } /** * Gets the <tt>ResourceManagementService</tt> instance which represents the resources such as * internationalized and localized text and images used by the neomedia bundle. * * @return the <tt>ResourceManagementService</tt> instance which represents the resources such as * internationalized and localized text and images used by the neomedia bundle */ public static ResourceManagementService getResources() { if (resources == null) { resources = ResourceManagementServiceUtils.getService(bundleContext); } return resources; } /** * Returns a reference to the <tt>PacketLoggingService</tt> implementation currently registered in * the bundle context or null if no such implementation was found. * * @return a reference to a <tt>PacketLoggingService</tt> implementation currently registered in * the bundle context or null if no such implementation was found. */ public static PacketLoggingService getPacketLogging() { if (packetLoggingService == null) { packetLoggingService = ServiceUtils.getService(bundleContext, PacketLoggingService.class); } return packetLoggingService; } /** * Returns the <tt>NotificationService</tt> obtained from the bundle context. * * @return The <tt>NotificationService</tt> obtained from the bundle context. */ public static NotificationService getNotificationService() { if (notificationService == null) { // Get the notification service implementation ServiceReference notifReference = bundleContext.getServiceReference(NotificationService.class.getName()); notificationService = (NotificationService) bundleContext.getService(notifReference); if (notificationService != null) { // Register a popup message for a device configuration changed // notification. notificationService.registerDefaultNotificationForEvent( DEVICE_CONFIGURATION_HAS_CHANGED, net.java.sip.communicator.service.notification.NotificationAction.ACTION_POPUP_MESSAGE, "Device onfiguration has changed", null); } } return notificationService; } /** A listener to the click on the popup message concerning device configuration changes. */ private class AudioDeviceConfigurationListener implements PropertyChangeListener /*, SystrayPopupMessageListener*/ { /** * A boolean used to verify that this listener registers only once to the popup message * notification handler. */ private boolean isRegisteredToPopupMessageListener = false; /** * Registers or unregister as a popup message listener to detect when a user click on * notification saying that the device configuration has changed. * * @param enable True to register to the popup message notifcation handler. False to unregister. */ public void managePopupMessageListenerRegistration(boolean enable) { Iterator<NotificationHandler> notificationHandlers = notificationService .getActionHandlers( net.java.sip.communicator.service.notification.NotificationAction .ACTION_POPUP_MESSAGE) .iterator(); NotificationHandler notificationHandler; while (notificationHandlers.hasNext()) { notificationHandler = notificationHandlers.next(); if (notificationHandler instanceof PopupMessageNotificationHandler) { // Register. if (enable) { // ((PopupMessageNotificationHandler) notificationHandler) // .addPopupMessageListener(this); } // Unregister. else { // ((PopupMessageNotificationHandler) notificationHandler) // .removePopupMessageListener(this); } } } } /** * Function called when an audio device is plugged or unplugged. * * @param event The property change event which may concern the audio device. */ public void propertyChange(PropertyChangeEvent event) { if (DeviceConfiguration.PROP_AUDIO_SYSTEM_DEVICES.equals(event.getPropertyName())) { NotificationService notificationService = getNotificationService(); if (notificationService != null) { // Registers only once to the popup message notification // handler. if (!isRegisteredToPopupMessageListener) { isRegisteredToPopupMessageListener = true; managePopupMessageListenerRegistration(true); } // Fires the popup notification. ResourceManagementService resources = NeomediaActivator.getResources(); Map<String, Object> extras = new HashMap<String, Object>(); extras.put(NotificationData.POPUP_MESSAGE_HANDLER_TAG_EXTRA, this); notificationService.fireNotification( DEVICE_CONFIGURATION_HAS_CHANGED, resources.getI18NString("impl.media.configform" + ".AUDIO_DEVICE_CONFIG_CHANGED"), resources.getI18NString( "impl.media.configform" + ".AUDIO_DEVICE_CONFIG_MANAGMENT_CLICK"), null, extras); } } } /** * Indicates that user has clicked on the systray popup message. * * @param evt the event triggered when user clicks on the systray popup message */ // public void popupMessageClicked(SystrayPopupMessageEvent evt) // { // // Checks if this event is fired from one click on one of our popup // // message. // if(evt.getTag() == deviceConfigurationPropertyChangeListener) // { // // Get the UI service // ServiceReference uiReference = bundleContext // .getServiceReference(UIService.class.getStatus()); // // UIService uiService = (UIService) bundleContext // .getService(uiReference); // // if(uiService != null) // { // // Shows the audio configuration window. // ConfigurationContainer configurationContainer // = uiService.getConfigurationContainer(); // configurationContainer.setSelected(audioConfigurationForm); // configurationContainer.setVisible(true); // } // } // } } public static BundleContext getBundleContext() { return bundleContext; } }
/** * Keeps track of entity capabilities. * * <p>This work is based on Jonas Adahl's smack fork. * * @author Emil Ivov * @author Lyubomir Marinov */ public class EntityCapsManager { /** * The <tt>Logger</tt> used by the <tt>EntityCapsManager</tt> class and its instances for logging * output. */ private static final Logger logger = Logger.getLogger(EntityCapsManager.class); /** Static OSGi bundle context used by this class. */ private static BundleContext bundleContext; /** Configuration service instance used by this class. */ private static ConfigurationService configService; /** * The prefix of the <tt>ConfigurationService</tt> properties which persist {@link * #caps2discoverInfo}. */ private static final String CAPS_PROPERTY_NAME_PREFIX = "net.java.sip.communicator.impl.protocol.jabber.extensions.caps." + "EntityCapsManager.CAPS."; /** * An empty array of <tt>UserCapsNodeListener</tt> elements explicitly defined in order to reduce * unnecessary allocations. */ private static final UserCapsNodeListener[] NO_USER_CAPS_NODE_LISTENERS = new UserCapsNodeListener[0]; /** The node value to advertise. */ private static String entityNode = OSUtils.IS_ANDROID ? "http://android.jitsi.org" : "http://jitsi.org"; /** * The <tt>Map</tt> of <tt>Caps</tt> to <tt>DiscoverInfo</tt> which associates a node#ver with the * entity capabilities so that they don't have to be retrieved every time their necessary. Because * ver is constructed from the entity capabilities using a specific hash method, the hash method * is also associated with the entity capabilities along with the node and the ver in order to * disambiguate cases of equal ver values for different entity capabilities constructed using * different hash methods. */ private static final Map<Caps, DiscoverInfo> caps2discoverInfo = new ConcurrentHashMap<Caps, DiscoverInfo>(); /** * Map of Full JID -> DiscoverInfo/null. In case of c2s connection the key is formed as * user@server/resource (resource is required) In case of link-local connection the key is formed * as user@host (no resource) */ private final Map<String, Caps> userCaps = new ConcurrentHashMap<String, Caps>(); /** CapsVerListeners gets notified when the version string is changed. */ private final Set<CapsVerListener> capsVerListeners = new CopyOnWriteArraySet<CapsVerListener>(); /** The current hash of our version and supported features. */ private String currentCapsVersion = null; /** * The list of <tt>UserCapsNodeListener</tt>s interested in events notifying about changes in the * list of user caps nodes of this <tt>EntityCapsManager</tt>. */ private final List<UserCapsNodeListener> userCapsNodeListeners = new LinkedList<UserCapsNodeListener>(); static { ProviderManager.getInstance() .addExtensionProvider( CapsPacketExtension.ELEMENT_NAME, CapsPacketExtension.NAMESPACE, new CapsProvider()); } /** * Add {@link DiscoverInfo} to our caps database. * * <p><b>Warning</b>: The specified <tt>DiscoverInfo</tt> is trusted to be valid with respect to * the specified <tt>Caps</tt> for performance reasons because the <tt>DiscoverInfo</tt> should * have already been validated in order to be used elsewhere anyway. * * @param caps the <tt>Caps<tt/> i.e. the node, the hash and the ver for which a * <tt>DiscoverInfo</tt> is to be added to our caps database. * @param info {@link DiscoverInfo} for the specified <tt>Caps</tt>. */ public static void addDiscoverInfoByCaps(Caps caps, DiscoverInfo info) { cleanupDiscoverInfo(info); /* * DiscoverInfo carries the node we're now associating it with a * specific node so we'd better keep them in sync. */ info.setNode(caps.getNodeVer()); synchronized (caps2discoverInfo) { DiscoverInfo oldInfo = caps2discoverInfo.put(caps, info); /* * If the specified info is a new association for the specified * node, remember it across application instances in order to not * query for it over the network. */ if ((oldInfo == null) || !oldInfo.equals(info)) { String xml = info.getChildElementXML(); if ((xml != null) && (xml.length() != 0)) { getConfigService().setProperty(getCapsPropertyName(caps), xml); } } } } /** * Gets the name of the property in the <tt>ConfigurationService</tt> which is or is to be * associated with a specific <tt>Caps</tt> value. * * @param caps the <tt>Caps</tt> value for which the associated <tt>ConfigurationService</tt> * property name is to be returned * @return the name of the property in the <tt>ConfigurationService</tt> which is or is to be * associated with a specific <tt>Caps</tt> value */ private static String getCapsPropertyName(Caps caps) { return CAPS_PROPERTY_NAME_PREFIX + caps.node + '#' + caps.hash + '#' + caps.ver; } /** Returns cached instance of {@link ConfigurationService}. */ private static ConfigurationService getConfigService() { if (configService == null) { configService = ServiceUtils.getService(bundleContext, ConfigurationService.class); } return configService; } /** * Sets OSGi bundle context instance that will be used by this class. * * @param bundleContext the <tt>BundleContext</tt> instance to be used by this class or * <tt>null</tt> to clear the reference. */ public static void setBundleContext(BundleContext bundleContext) { if (bundleContext == null) { configService = null; } EntityCapsManager.bundleContext = bundleContext; } /** * Add a record telling what entity caps node a user has. * * @param user the user (Full JID) * @param node the node (of the caps packet extension) * @param hash the hashing algorithm used to calculate <tt>ver</tt> * @param ver the version (of the caps packet extension) * @param ext the ext (of the caps packet extension) * @param online indicates if the user is online */ private void addUserCapsNode( String user, String node, String hash, String ver, String ext, boolean online) { if ((user != null) && (node != null) && (hash != null) && (ver != null)) { Caps caps = userCaps.get(user); if ((caps == null) || !caps.node.equals(node) || !caps.hash.equals(hash) || !caps.ver.equals(ver)) { caps = new Caps(node, hash, ver, ext); userCaps.put(user, caps); } else return; // Fire userCapsNodeAdded. UserCapsNodeListener[] listeners; synchronized (userCapsNodeListeners) { listeners = userCapsNodeListeners.toArray(NO_USER_CAPS_NODE_LISTENERS); } if (listeners.length != 0) { String nodeVer = caps.getNodeVer(); for (UserCapsNodeListener listener : listeners) listener.userCapsNodeAdded(user, nodeVer, online); } } } /** * Adds a specific <tt>UserCapsNodeListener</tt> to the list of <tt>UserCapsNodeListener</tt>s * interested in events notifying about changes in the list of user caps nodes of this * <tt>EntityCapsManager</tt>. * * @param listener the <tt>UserCapsNodeListener</tt> which is interested in events notifying about * changes in the list of user caps nodes of this <tt>EntityCapsManager</tt> */ public void addUserCapsNodeListener(UserCapsNodeListener listener) { if (listener == null) throw new NullPointerException("listener"); synchronized (userCapsNodeListeners) { if (!userCapsNodeListeners.contains(listener)) userCapsNodeListeners.add(listener); } } /** * Remove records telling what entity caps node a contact has. * * @param contact the contact */ public void removeContactCapsNode(Contact contact) { Caps caps = null; String lastRemovedJid = null; Iterator<String> iter = userCaps.keySet().iterator(); while (iter.hasNext()) { String jid = iter.next(); if (StringUtils.parseBareAddress(jid).equals(contact.getAddress())) { caps = userCaps.get(jid); lastRemovedJid = jid; iter.remove(); } } // fire only for the last one, at the end the event out // of the protocol will be one and for the contact if (caps != null) { UserCapsNodeListener[] listeners; synchronized (userCapsNodeListeners) { listeners = userCapsNodeListeners.toArray(NO_USER_CAPS_NODE_LISTENERS); } if (listeners.length != 0) { String nodeVer = caps.getNodeVer(); for (UserCapsNodeListener listener : listeners) listener.userCapsNodeRemoved(lastRemovedJid, nodeVer, false); } } } /** * Remove a record telling what entity caps node a user has. * * @param user the user (Full JID) */ public void removeUserCapsNode(String user) { Caps caps = userCaps.remove(user); // Fire userCapsNodeRemoved. if (caps != null) { UserCapsNodeListener[] listeners; synchronized (userCapsNodeListeners) { listeners = userCapsNodeListeners.toArray(NO_USER_CAPS_NODE_LISTENERS); } if (listeners.length != 0) { String nodeVer = caps.getNodeVer(); for (UserCapsNodeListener listener : listeners) listener.userCapsNodeRemoved(user, nodeVer, false); } } } /** * Removes a specific <tt>UserCapsNodeListener</tt> from the list of * <tt>UserCapsNodeListener</tt>s interested in events notifying about changes in the list of user * caps nodes of this <tt>EntityCapsManager</tt>. * * @param listener the <tt>UserCapsNodeListener</tt> which is no longer interested in events * notifying about changes in the list of user caps nodes of this <tt>EntityCapsManager</tt> */ public void removeUserCapsNodeListener(UserCapsNodeListener listener) { if (listener != null) { synchronized (userCapsNodeListeners) { userCapsNodeListeners.remove(listener); } } } /** * Gets the <tt>Caps</tt> i.e. the node, the hash and the ver of a user. * * @param user the user (Full JID) * @return the <tt>Caps</tt> i.e. the node, the hash and the ver of <tt>user</tt> */ public Caps getCapsByUser(String user) { return userCaps.get(user); } /** * Get the discover info given a user name. The discover info is returned if the user has a * node#ver associated with it and the node#ver has a discover info associated with it. * * @param user user name (Full JID) * @return the discovered info */ public DiscoverInfo getDiscoverInfoByUser(String user) { Caps caps = userCaps.get(user); return (caps == null) ? null : getDiscoverInfoByCaps(caps); } /** * Get our own caps version. * * @return our own caps version */ public String getCapsVersion() { return currentCapsVersion; } /** * Get our own entity node. * * @return our own entity node. */ public String getNode() { return entityNode; } /** * Set our own entity node. * * @param node the new node */ public void setNode(String node) { entityNode = node; } /** * Retrieve DiscoverInfo for a specific node. * * @param caps the <tt>Caps</tt> i.e. the node, the hash and the ver * @return The corresponding DiscoverInfo or null if none is known. */ public static DiscoverInfo getDiscoverInfoByCaps(Caps caps) { synchronized (caps2discoverInfo) { DiscoverInfo discoverInfo = caps2discoverInfo.get(caps); /* * If we don't have the discoverInfo in the runtime cache yet, we * may have it remembered in a previous application instance. */ if (discoverInfo == null) { ConfigurationService configurationService = getConfigService(); String capsPropertyName = getCapsPropertyName(caps); String xml = configurationService.getString(capsPropertyName); if ((xml != null) && (xml.length() != 0)) { IQProvider discoverInfoProvider = (IQProvider) ProviderManager.getInstance() .getIQProvider("query", "http://jabber.org/protocol/disco#info"); if (discoverInfoProvider != null) { XmlPullParser parser = new MXParser(); try { parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); parser.setInput(new StringReader(xml)); // Start the parser. parser.next(); } catch (XmlPullParserException xppex) { parser = null; } catch (IOException ioex) { parser = null; } if (parser != null) { try { discoverInfo = (DiscoverInfo) discoverInfoProvider.parseIQ(parser); } catch (Exception ex) { } if (discoverInfo != null) { if (caps.isValid(discoverInfo)) caps2discoverInfo.put(caps, discoverInfo); else { logger.error( "Invalid DiscoverInfo for " + caps.getNodeVer() + ": " + discoverInfo); /* * The discoverInfo doesn't seem valid * according to the caps which means that we * must have stored invalid information. * Delete the invalid information in order * to not try to validate it again. */ configurationService.removeProperty(capsPropertyName); } } } } } } return discoverInfo; } } /** * Removes from, to and packet-id from <tt>info</tt>. * * @param info the {@link DiscoverInfo} that we'd like to cleanup. */ private static void cleanupDiscoverInfo(DiscoverInfo info) { info.setFrom(null); info.setTo(null); info.setPacketID(null); } /** * Gets the features of a specific <tt>DiscoverInfo</tt> in the form of a read-only * <tt>Feature</tt> <tt>Iterator<tt/> by calling the internal method {@link * DiscoverInfo#getFeatures()}. * * @param discoverInfo the <tt>DiscoverInfo</tt> the features of which are to be retrieved * @return a read-only <tt>Feature</tt> <tt>Iterator</tt> which lists the features of the * specified <tt>discoverInfo</tt> */ @SuppressWarnings("unchecked") private static Iterator<DiscoverInfo.Feature> getDiscoverInfoFeatures(DiscoverInfo discoverInfo) { Method getFeaturesMethod; try { getFeaturesMethod = DiscoverInfo.class.getDeclaredMethod("getFeatures"); } catch (NoSuchMethodException nsmex) { throw new UndeclaredThrowableException(nsmex); } getFeaturesMethod.setAccessible(true); try { return (Iterator<DiscoverInfo.Feature>) getFeaturesMethod.invoke(discoverInfo); } catch (IllegalAccessException iaex) { throw new UndeclaredThrowableException(iaex); } catch (InvocationTargetException itex) { throw new UndeclaredThrowableException(itex); } } /** * Registers this Manager's listener with <tt>connection</tt>. * * @param connection the connection that we'd like this manager to register with. */ public void addPacketListener(XMPPConnection connection) { PacketFilter filter = new AndFilter( new PacketTypeFilter(Presence.class), new PacketExtensionFilter( CapsPacketExtension.ELEMENT_NAME, CapsPacketExtension.NAMESPACE)); connection.addPacketListener(new CapsPacketListener(), filter); } /** * Adds <tt>listener</tt> to the list of {@link CapsVerListener}s that we notify when new features * occur and the version hash needs to be regenerated. The method would also notify * <tt>listener</tt> if our current caps version has been generated and is different than * <tt>null</tt>. * * @param listener the {@link CapsVerListener} we'd like to register. */ public void addCapsVerListener(CapsVerListener listener) { synchronized (capsVerListeners) { if (capsVerListeners.contains(listener)) return; capsVerListeners.add(listener); if (currentCapsVersion != null) listener.capsVerUpdated(currentCapsVersion); } } /** * Removes <tt>listener</tt> from the list of currently registered {@link CapsVerListener}s. * * @param listener the {@link CapsVerListener} we'd like to unregister. */ public void removeCapsVerListener(CapsVerListener listener) { synchronized (capsVerListeners) { capsVerListeners.remove(listener); } } /** * Notifies all currently registered {@link CapsVerListener}s that the version hash has changed. */ private void fireCapsVerChanged() { List<CapsVerListener> listenersCopy = null; synchronized (capsVerListeners) { listenersCopy = new ArrayList<CapsVerListener>(capsVerListeners); } for (CapsVerListener listener : listenersCopy) listener.capsVerUpdated(currentCapsVersion); } /** * Computes and returns the hash of the specified <tt>capsString</tt> using the specified * <tt>hashAlgorithm</tt>. * * @param hashAlgorithm the name of the algorithm to be used to generate the hash * @param capsString the capabilities string that we'd like to compute a hash for. * @return the hash of <tt>capsString</tt> computed by the specified <tt>hashAlgorithm</tt> or * <tt>null</tt> if generating the hash has failed */ private static String capsToHash(String hashAlgorithm, String capsString) { try { MessageDigest md = MessageDigest.getInstance(hashAlgorithm); byte[] digest = md.digest(capsString.getBytes()); return Base64.encodeBytes(digest); } catch (NoSuchAlgorithmException nsae) { logger.error("Unsupported XEP-0115: Entity Capabilities hash algorithm: " + hashAlgorithm); return null; } } /** * Converts the form field values in the <tt>ffValuesIter</tt> into a caps string. * * @param ffValuesIter the {@link Iterator} containing the form field values. * @param capsBldr a <tt>StringBuilder</tt> to which the caps string representing the form field * values is to be appended */ private static void formFieldValuesToCaps(Iterator<String> ffValuesIter, StringBuilder capsBldr) { SortedSet<String> fvs = new TreeSet<String>(); while (ffValuesIter.hasNext()) fvs.add(ffValuesIter.next()); for (String fv : fvs) capsBldr.append(fv).append('<'); } /** * Calculates the <tt>String</tt> for a specific <tt>DiscoverInfo</tt> which is to be hashed in * order to compute the ver string for that <tt>DiscoverInfo</tt>. * * @param discoverInfo the <tt>DiscoverInfo</tt> for which the <tt>String</tt> to be hashed in * order to compute its ver string is to be calculated * @return the <tt>String</tt> for <tt>discoverInfo</tt> which is to be hashed in order to compute * its ver string */ private static String calculateEntityCapsString(DiscoverInfo discoverInfo) { StringBuilder bldr = new StringBuilder(); // Add identities { Iterator<DiscoverInfo.Identity> identities = discoverInfo.getIdentities(); SortedSet<DiscoverInfo.Identity> is = new TreeSet<DiscoverInfo.Identity>( new Comparator<DiscoverInfo.Identity>() { public int compare(DiscoverInfo.Identity i1, DiscoverInfo.Identity i2) { int category = i1.getCategory().compareTo(i2.getCategory()); if (category != 0) return category; int type = i1.getType().compareTo(i2.getType()); if (type != 0) return type; /* * TODO Sort by xml:lang. * * Since sort by xml:lang is currently missing, * use the last supported sort criterion i.e. * type. */ return type; } }); if (identities != null) while (identities.hasNext()) is.add(identities.next()); for (DiscoverInfo.Identity i : is) { bldr.append(i.getCategory()) .append('/') .append(i.getType()) .append("//") .append(i.getName()) .append('<'); } } // Add features { Iterator<DiscoverInfo.Feature> features = getDiscoverInfoFeatures(discoverInfo); SortedSet<String> fs = new TreeSet<String>(); if (features != null) while (features.hasNext()) fs.add(features.next().getVar()); for (String f : fs) bldr.append(f).append('<'); } DataForm extendedInfo = (DataForm) discoverInfo.getExtension("x", "jabber:x:data"); if (extendedInfo != null) { synchronized (extendedInfo) { SortedSet<FormField> fs = new TreeSet<FormField>( new Comparator<FormField>() { public int compare(FormField f1, FormField f2) { return f1.getVariable().compareTo(f2.getVariable()); } }); FormField formType = null; for (Iterator<FormField> fieldsIter = extendedInfo.getFields(); fieldsIter.hasNext(); ) { FormField f = fieldsIter.next(); if (!f.getVariable().equals("FORM_TYPE")) fs.add(f); else formType = f; } // Add FORM_TYPE values if (formType != null) formFieldValuesToCaps(formType.getValues(), bldr); // Add the other values for (FormField f : fs) { bldr.append(f.getVariable()).append('<'); formFieldValuesToCaps(f.getValues(), bldr); } } } return bldr.toString(); } /** * Calculates the ver string for the specified <tt>discoverInfo</tt>, identity type, name * features, and extendedInfo. * * @param discoverInfo the {@link DiscoverInfo} we'd be creating a ver <tt>String</tt> for */ public void calculateEntityCapsVersion(DiscoverInfo discoverInfo) { setCurrentCapsVersion( discoverInfo, capsToHash(CapsPacketExtension.HASH_METHOD, calculateEntityCapsString(discoverInfo))); } /** * Set our own caps version. * * @param discoverInfo the {@link DiscoverInfo} that we'd like to map to the <tt>capsVersion</tt>. * @param capsVersion the new caps version */ public void setCurrentCapsVersion(DiscoverInfo discoverInfo, String capsVersion) { Caps caps = new Caps(getNode(), CapsPacketExtension.HASH_METHOD, capsVersion, null); /* * DiscoverInfo carries the node and the ver and we're now setting a new * ver so we should update the DiscoveryInfo. */ discoverInfo.setNode(caps.getNodeVer()); if (!caps.isValid(discoverInfo)) { throw new IllegalArgumentException( "The specified discoverInfo must be valid with respect" + " to the specified capsVersion"); } currentCapsVersion = capsVersion; addDiscoverInfoByCaps(caps, discoverInfo); fireCapsVerChanged(); } /** The {@link PacketListener} that will be registering incoming caps. */ private class CapsPacketListener implements PacketListener { /** * Handles incoming presence packets and maps jids to node#ver strings. * * @param packet the incoming presence <tt>Packet</tt> to be handled * @see PacketListener#processPacket(Packet) */ public void processPacket(Packet packet) { CapsPacketExtension ext = (CapsPacketExtension) packet.getExtension(CapsPacketExtension.ELEMENT_NAME, CapsPacketExtension.NAMESPACE); /* * Before Version 1.4 of XEP-0115: Entity Capabilities, the 'ver' * attribute was generated differently and the 'hash' attribute was * absent. The 'ver' attribute in Version 1.3 represents the * specific version of the client and thus does not provide a way to * validate the DiscoverInfo sent by the client. If * EntityCapsManager receives no 'hash' attribute, it will assume * the legacy format and will not cache it because the DiscoverInfo * to be received from the client later on will not be trustworthy. */ String hash = ext.getHash(); /* Google Talk web does not set hash but we need it to be cached */ if (hash == null) hash = ""; if (hash != null) { // Check it the packet indicates that the user is online. We // will use this information to decide if we're going to send // the discover info request. boolean online = (packet instanceof Presence) && ((Presence) packet).isAvailable(); if (online) { addUserCapsNode( packet.getFrom(), ext.getNode(), hash, ext.getVersion(), ext.getExtensions(), online); } else { removeUserCapsNode(packet.getFrom()); } } } } /** * Implements an immutable value which stands for a specific node, a specific hash (algorithm) and * a specific ver. * * @author Lyubomir Marinov */ public static class Caps { /** The hash (algorithm) of this <tt>Caps</tt> value. */ public final String hash; /** The node of this <tt>Caps</tt> value. */ public final String node; /** The ext info of this <tt>Caps</tt> value. */ public String ext; /** * The String which is the concatenation of {@link #node} and the {@link #ver} separated by the * character '#'. Cached for the sake of efficiency. */ private final String nodeVer; /** The ver of this <tt>Caps</tt> value. */ public final String ver; /** * Initializes a new <tt>Caps</tt> instance which is to represent a specific node, a specific * hash (algorithm) and a specific ver. * * @param node the node to be represented by the new instance * @param hash the hash (algorithm) to be represented by the new instance * @param ver the ver to be represented by the new instance * @param ext the ext to be represented by the new instance */ public Caps(String node, String hash, String ver, String ext) { if (node == null) throw new NullPointerException("node"); if (hash == null) throw new NullPointerException("hash"); if (ver == null) throw new NullPointerException("ver"); this.node = node; this.hash = hash; this.ver = ver; this.ext = ext; this.nodeVer = this.node + '#' + this.ver; } /** * Gets a <tt>String</tt> which represents the concatenation of the <tt>node</tt> property of * this instance, the character '#' and the <tt>ver</tt> property of this instance. * * @return a <tt>String</tt> which represents the concatenation of the <tt>node</tt> property of * this instance, the character '#' and the <tt>ver</tt> property of this instance */ public final String getNodeVer() { return nodeVer; } /** * Determines whether a specific <tt>DiscoverInfo</tt> is valid according to this <tt>Caps</tt> * i.e. whether the <tt>discoverInfo</tt> has the node and the ver of this <tt>Caps</tt> and the * ver calculated from the <tt>discoverInfo</tt> using the hash (algorithm) of this * <tt>Caps</tt> is equal to the ver of this <tt>Caps</tt>. * * @param discoverInfo the <tt>DiscoverInfo</tt> to be validated by this <tt>Caps</tt> * @return <tt>true</tt> if the specified <tt>DiscoverInfo</tt> has the node and the ver of this * <tt>Caps</tt> and the ver calculated from the <tt>discoverInfo</tt> using the hash * (algorithm) of this <tt>Caps</tt> is equal to the ver of this <tt>Caps</tt>; otherwise, * <tt>false</tt> */ public boolean isValid(DiscoverInfo discoverInfo) { if (discoverInfo != null) { // The "node" attribute is not necessary in the query element. // For example, Swift does not send back the "node" attribute in // the Disco#info response. Thus, if the node of the IQ response // is null, then we set it to the request one. if (discoverInfo.getNode() == null) { discoverInfo.setNode(getNodeVer()); } if (getNodeVer().equals(discoverInfo.getNode()) && !hash.equals("") && ver.equals(capsToHash(hash, calculateEntityCapsString(discoverInfo)))) { return true; } } return false; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Caps caps = (Caps) o; if (!hash.equals(caps.hash)) return false; if (!node.equals(caps.node)) return false; if (!ver.equals(caps.ver)) return false; return true; } @Override public int hashCode() { int result = hash.hashCode(); result = 31 * result + node.hashCode(); result = 31 * result + ver.hashCode(); return result; } } }
/** * The contactlist panel not only contains the contact list but it has the role of a message * dispatcher. It process all sent and received messages as well as all typing notifications. Here * are managed all contact list mouse events. * * @author Yana Stamcheva * @author Hristo Terezov */ public class ContactListPane extends SIPCommScrollPane implements MessageListener, TypingNotificationsListener, FileTransferListener, ContactListListener, PluginComponentListener { /** Serial version UID. */ private static final long serialVersionUID = 0L; private final MainFrame mainFrame; private TreeContactList contactList; private final TypingTimer typingTimer = new TypingTimer(); private CommonRightButtonMenu commonRightButtonMenu; private final Logger logger = Logger.getLogger(ContactListPane.class); private final ChatWindowManager chatWindowManager; /** * Creates the contactlist scroll panel defining the parent frame. * * @param mainFrame The parent frame. */ public ContactListPane(MainFrame mainFrame) { this.mainFrame = mainFrame; this.chatWindowManager = GuiActivator.getUIService().getChatWindowManager(); this.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); this.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY)); this.initPluginComponents(); } /** * Initializes the contact list. * * @param contactListService The MetaContactListService which will be used for a contact list data * model. */ public void initList(MetaContactListService contactListService) { this.contactList = new TreeContactList(mainFrame); // We should first set the contact list to the GuiActivator, so that // anybody could get it from there. GuiActivator.setContactList(contactList); // By default we set the current filter to be the presence filter. contactList.applyFilter(TreeContactList.presenceFilter); TransparentPanel transparentPanel = new TransparentPanel(new BorderLayout()); transparentPanel.add(contactList, BorderLayout.NORTH); this.setViewportView(transparentPanel); transparentPanel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); this.contactList.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); this.contactList.addContactListListener(this); this.addMouseListener( new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { commonRightButtonMenu = new CommonRightButtonMenu(mainFrame); commonRightButtonMenu.setInvoker(ContactListPane.this); commonRightButtonMenu.setLocation( e.getX() + mainFrame.getX() + 5, e.getY() + mainFrame.getY() + 105); commonRightButtonMenu.setVisible(true); } } }); } /** * Returns the contact list. * * @return the contact list */ public TreeContactList getContactList() { return this.contactList; } /** * Implements the ContactListListener.contactSelected method. * * @param evt the <tt>ContactListEvent</tt> that notified us */ public void contactClicked(ContactListEvent evt) { // We're interested only in two click events. if (evt.getClickCount() < 2) return; UIContact descriptor = evt.getSourceContact(); // We're currently only interested in MetaContacts. if (descriptor.getDescriptor() instanceof MetaContact) { MetaContact metaContact = (MetaContact) descriptor.getDescriptor(); // Searching for the right proto contact to use as default for the // chat conversation. Contact defaultContact = metaContact.getDefaultContact(OperationSetBasicInstantMessaging.class); // do nothing if (defaultContact == null) { defaultContact = metaContact.getDefaultContact(OperationSetSmsMessaging.class); if (defaultContact == null) return; } ProtocolProviderService defaultProvider = defaultContact.getProtocolProvider(); OperationSetBasicInstantMessaging defaultIM = defaultProvider.getOperationSet(OperationSetBasicInstantMessaging.class); ProtocolProviderService protoContactProvider; OperationSetBasicInstantMessaging protoContactIM; boolean isOfflineMessagingSupported = defaultIM != null && !defaultIM.isOfflineMessagingSupported(); if (defaultContact.getPresenceStatus().getStatus() < 1 && (!isOfflineMessagingSupported || !defaultProvider.isRegistered())) { Iterator<Contact> protoContacts = metaContact.getContacts(); while (protoContacts.hasNext()) { Contact contact = protoContacts.next(); protoContactProvider = contact.getProtocolProvider(); protoContactIM = protoContactProvider.getOperationSet(OperationSetBasicInstantMessaging.class); if (protoContactIM != null && protoContactIM.isOfflineMessagingSupported() && protoContactProvider.isRegistered()) { defaultContact = contact; } } } ContactEventHandler contactHandler = mainFrame.getContactHandler(defaultContact.getProtocolProvider()); contactHandler.contactClicked(defaultContact, evt.getClickCount()); } else if (descriptor.getDescriptor() instanceof SourceContact) { SourceContact contact = (SourceContact) descriptor.getDescriptor(); List<ContactDetail> imDetails = contact.getContactDetails(OperationSetBasicInstantMessaging.class); List<ContactDetail> mucDetails = contact.getContactDetails(OperationSetMultiUserChat.class); if (imDetails != null && imDetails.size() > 0) { ProtocolProviderService pps = imDetails.get(0).getPreferredProtocolProvider(OperationSetBasicInstantMessaging.class); GuiActivator.getUIService() .getChatWindowManager() .startChat(contact.getContactAddress(), pps); } else if (mucDetails != null && mucDetails.size() > 0) { ChatRoomWrapper room = GuiActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact); if (room == null) { // lets check by id ProtocolProviderService pps = mucDetails.get(0).getPreferredProtocolProvider(OperationSetMultiUserChat.class); room = GuiActivator.getMUCService() .findChatRoomWrapperFromChatRoomID(contact.getContactAddress(), pps); if (room == null) { GuiActivator.getMUCService() .createChatRoom( contact.getContactAddress(), pps, new ArrayList<String>(), "", false, false, false); } } if (room != null) GuiActivator.getMUCService().openChatRoom(room); } else { List<ContactDetail> smsDetails = contact.getContactDetails(OperationSetSmsMessaging.class); if (smsDetails != null && smsDetails.size() > 0) { GuiActivator.getUIService() .getChatWindowManager() .startChat(contact.getContactAddress(), true); } } } } /** * Implements the ContactListListener.groupSelected method. * * @param evt the <tt>ContactListEvent</tt> that notified us */ public void groupClicked(ContactListEvent evt) {} /** We're not interested in group selection events here. */ public void groupSelected(ContactListEvent evt) {} /** We're not interested in contact selection events here. */ public void contactSelected(ContactListEvent evt) {} /** * When a message is received determines whether to open a new chat window or chat window tab, or * to indicate that a message is received from a contact which already has an open chat. When the * chat is found checks if in mode "Auto popup enabled" and if this is the case shows the message * in the appropriate chat panel. * * @param evt the event containing details on the received message */ public void messageReceived(MessageReceivedEvent evt) { if (logger.isTraceEnabled()) logger.trace("MESSAGE RECEIVED from contact: " + evt.getSourceContact().getAddress()); Contact protocolContact = evt.getSourceContact(); ContactResource contactResource = evt.getContactResource(); Message message = evt.getSourceMessage(); int eventType = evt.getEventType(); MetaContact metaContact = GuiActivator.getContactListService().findMetaContactByContact(protocolContact); if (metaContact != null) { messageReceived( protocolContact, contactResource, metaContact, message, eventType, evt.getTimestamp(), evt.getCorrectedMessageUID(), evt.isPrivateMessaging(), evt.getPrivateMessagingContactRoom()); } else { if (logger.isTraceEnabled()) logger.trace("MetaContact not found for protocol contact: " + protocolContact + "."); } } /** * When a message is received determines whether to open a new chat window or chat window tab, or * to indicate that a message is received from a contact which already has an open chat. When the * chat is found checks if in mode "Auto popup enabled" and if this is the case shows the message * in the appropriate chat panel. * * @param protocolContact the source contact of the event * @param contactResource the resource from which the contact is writing * @param metaContact the metacontact containing <tt>protocolContact</tt> * @param message the message to deliver * @param eventType the event type * @param timestamp the timestamp of the event * @param correctedMessageUID the identifier of the corrected message * @param isPrivateMessaging if <tt>true</tt> the message is received from private messaging * contact. * @param privateContactRoom the chat room associated with the private messaging contact. */ private void messageReceived( final Contact protocolContact, final ContactResource contactResource, final MetaContact metaContact, final Message message, final int eventType, final Date timestamp, final String correctedMessageUID, final boolean isPrivateMessaging, final ChatRoom privateContactRoom) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater( new Runnable() { public void run() { messageReceived( protocolContact, contactResource, metaContact, message, eventType, timestamp, correctedMessageUID, isPrivateMessaging, privateContactRoom); } }); return; } // Obtain the corresponding chat panel. final ChatPanel chatPanel = chatWindowManager.getContactChat( metaContact, protocolContact, contactResource, message.getMessageUID()); // Show an envelope on the sender contact in the contact list and // in the systray. if (!chatPanel.isChatFocused()) contactList.setActiveContact(metaContact, true); // Distinguish the message type, depending on the type of event that // we have received. String messageType = null; if (eventType == MessageReceivedEvent.CONVERSATION_MESSAGE_RECEIVED) { messageType = Chat.INCOMING_MESSAGE; } else if (eventType == MessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED) { messageType = Chat.SYSTEM_MESSAGE; } else if (eventType == MessageReceivedEvent.SMS_MESSAGE_RECEIVED) { messageType = Chat.SMS_MESSAGE; } String contactAddress = (contactResource != null) ? protocolContact.getAddress() + " (" + contactResource.getResourceName() + ")" : protocolContact.getAddress(); chatPanel.addMessage( contactAddress, protocolContact.getDisplayName(), timestamp, messageType, message.getContent(), message.getContentType(), message.getMessageUID(), correctedMessageUID); String resourceName = (contactResource != null) ? contactResource.getResourceName() : null; if (isPrivateMessaging) { chatWindowManager.openPrivateChatForChatRoomMember(privateContactRoom, protocolContact); } else { chatWindowManager.openChat(chatPanel, false); } ChatTransport chatTransport = chatPanel.getChatSession().findChatTransportForDescriptor(protocolContact, resourceName); chatPanel.setSelectedChatTransport(chatTransport, true); } /** * When a sent message is delivered shows it in the chat conversation panel. * * @param evt the event containing details on the message delivery */ public void messageDelivered(MessageDeliveredEvent evt) { Contact contact = evt.getDestinationContact(); MetaContact metaContact = GuiActivator.getContactListService().findMetaContactByContact(contact); if (logger.isTraceEnabled()) logger.trace("MESSAGE DELIVERED to contact: " + contact.getAddress()); ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, false); if (chatPanel != null) { Message msg = evt.getSourceMessage(); ProtocolProviderService protocolProvider = contact.getProtocolProvider(); if (logger.isTraceEnabled()) logger.trace( "MESSAGE DELIVERED: process message to chat for contact: " + contact.getAddress() + " MESSAGE: " + msg.getContent()); chatPanel.addMessage( this.mainFrame.getAccountAddress(protocolProvider), this.mainFrame.getAccountDisplayName(protocolProvider), evt.getTimestamp(), Chat.OUTGOING_MESSAGE, msg.getContent(), msg.getContentType(), msg.getMessageUID(), evt.getCorrectedMessageUID()); if (evt.isSmsMessage() && !ConfigurationUtils.isSmsNotifyTextDisabled()) { chatPanel.addMessage( contact.getDisplayName(), new Date(), Chat.ACTION_MESSAGE, GuiActivator.getResources().getI18NString("service.gui.SMS_SUCCESSFULLY_SENT"), "text"); } } } /** * Shows a warning message to the user when message delivery has failed. * * @param evt the event containing details on the message delivery failure */ public void messageDeliveryFailed(MessageDeliveryFailedEvent evt) { logger.error(evt.getReason()); String errorMsg = null; Message sourceMessage = (Message) evt.getSource(); Contact sourceContact = evt.getDestinationContact(); MetaContact metaContact = GuiActivator.getContactListService().findMetaContactByContact(sourceContact); if (evt.getErrorCode() == MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED) { errorMsg = GuiActivator.getResources() .getI18NString( "service.gui.MSG_DELIVERY_NOT_SUPPORTED", new String[] {sourceContact.getDisplayName()}); } else if (evt.getErrorCode() == MessageDeliveryFailedEvent.NETWORK_FAILURE) { errorMsg = GuiActivator.getResources().getI18NString("service.gui.MSG_NOT_DELIVERED"); } else if (evt.getErrorCode() == MessageDeliveryFailedEvent.PROVIDER_NOT_REGISTERED) { errorMsg = GuiActivator.getResources().getI18NString("service.gui.MSG_SEND_CONNECTION_PROBLEM"); } else if (evt.getErrorCode() == MessageDeliveryFailedEvent.INTERNAL_ERROR) { errorMsg = GuiActivator.getResources().getI18NString("service.gui.MSG_DELIVERY_INTERNAL_ERROR"); } else { errorMsg = GuiActivator.getResources().getI18NString("service.gui.MSG_DELIVERY_ERROR"); } String reason = evt.getReason(); if (reason != null) errorMsg += " " + GuiActivator.getResources() .getI18NString("service.gui.ERROR_WAS", new String[] {reason}); ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, sourceContact); chatPanel.addMessage( sourceContact.getAddress(), metaContact.getDisplayName(), new Date(), Chat.OUTGOING_MESSAGE, sourceMessage.getContent(), sourceMessage.getContentType(), sourceMessage.getMessageUID(), evt.getCorrectedMessageUID()); chatPanel.addErrorMessage(metaContact.getDisplayName(), errorMsg); chatWindowManager.openChat(chatPanel, false); } /** * Informs the user what is the typing state of his chat contacts. * * @param evt the event containing details on the typing notification */ public void typingNotificationReceived(TypingNotificationEvent evt) { if (typingTimer.isRunning()) typingTimer.stop(); String notificationMsg = ""; MetaContact metaContact = GuiActivator.getContactListService().findMetaContactByContact(evt.getSourceContact()); String contactName = metaContact.getDisplayName() + " "; if (contactName.equals("")) { contactName = GuiActivator.getResources().getI18NString("service.gui.UNKNOWN") + " "; } int typingState = evt.getTypingState(); ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, false); if (typingState == OperationSetTypingNotifications.STATE_TYPING) { notificationMsg = GuiActivator.getResources() .getI18NString("service.gui.CONTACT_TYPING", new String[] {contactName}); // Proactive typing notification if (!chatWindowManager.isChatOpenedFor(metaContact)) { return; } if (chatPanel != null) chatPanel.addTypingNotification(notificationMsg); typingTimer.setMetaContact(metaContact); typingTimer.start(); } else if (typingState == OperationSetTypingNotifications.STATE_PAUSED) { notificationMsg = GuiActivator.getResources() .getI18NString("service.gui.CONTACT_PAUSED_TYPING", new String[] {contactName}); if (chatPanel != null) chatPanel.addTypingNotification(notificationMsg); typingTimer.setMetaContact(metaContact); typingTimer.start(); } else { if (chatPanel != null) chatPanel.removeTypingNotification(); } } /** * Called to indicate that sending typing notification has failed. * * @param evt a <tt>TypingNotificationEvent</tt> containing the sender of the notification and its * type. */ public void typingNotificationDeliveryFailed(TypingNotificationEvent evt) { if (typingTimer.isRunning()) typingTimer.stop(); String notificationMsg = ""; MetaContact metaContact = GuiActivator.getContactListService().findMetaContactByContact(evt.getSourceContact()); String contactName = metaContact.getDisplayName(); if (contactName.equals("")) { contactName = GuiActivator.getResources().getI18NString("service.gui.UNKNOWN") + " "; } ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, false); notificationMsg = GuiActivator.getResources() .getI18NString("service.gui.CONTACT_TYPING_SEND_FAILED", new String[] {contactName}); // Proactive typing notification if (!chatWindowManager.isChatOpenedFor(metaContact)) { return; } if (chatPanel != null) chatPanel.addErrorSendingTypingNotification(notificationMsg); typingTimer.setMetaContact(metaContact); typingTimer.start(); } /** * When a request has been received we show it to the user through the chat session renderer. * * @param event <tt>FileTransferRequestEvent</tt> * @see FileTransferListener#fileTransferRequestReceived(FileTransferRequestEvent) */ public void fileTransferRequestReceived(FileTransferRequestEvent event) { IncomingFileTransferRequest request = event.getRequest(); Contact sourceContact = request.getSender(); MetaContact metaContact = GuiActivator.getContactListService().findMetaContactByContact(sourceContact); final ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, sourceContact); chatPanel.addIncomingFileTransferRequest( event.getFileTransferOperationSet(), request, event.getTimestamp()); ChatTransport chatTransport = chatPanel.getChatSession().findChatTransportForDescriptor(sourceContact, null); chatPanel.setSelectedChatTransport(chatTransport, true); // Opens the chat panel with the new message in the UI thread. chatWindowManager.openChat(chatPanel, false); } /** * Nothing to do here, because we already know when a file transfer is created. * * @param event the <tt>FileTransferCreatedEvent</tt> that notified us */ public void fileTransferCreated(FileTransferCreatedEvent event) {} /** * Called when a new <tt>IncomingFileTransferRequest</tt> has been rejected. Nothing to do here, * because we are the one who rejects the request. * * @param event the <tt>FileTransferRequestEvent</tt> containing the received request which was * rejected. */ public void fileTransferRequestRejected(FileTransferRequestEvent event) {} /** * Called when an <tt>IncomingFileTransferRequest</tt> has been canceled from the contact who sent * it. * * @param event the <tt>FileTransferRequestEvent</tt> containing the request which was canceled. */ public void fileTransferRequestCanceled(FileTransferRequestEvent event) {} /** * Returns the right button menu of the contact list. * * @return the right button menu of the contact list */ public CommonRightButtonMenu getCommonRightButtonMenu() { return commonRightButtonMenu; } /** * The TypingTimer is started after a PAUSED typing notification is received. It waits 5 seconds * and if no other typing event occurs removes the PAUSED message from the chat status panel. */ private class TypingTimer extends Timer { /** Serial version UID. */ private static final long serialVersionUID = 0L; private MetaContact metaContact; public TypingTimer() { // Set delay super(5 * 1000, null); this.addActionListener(new TimerActionListener()); } private class TimerActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, false); if (chatPanel != null) chatPanel.removeTypingNotification(); } } private void setMetaContact(MetaContact metaContact) { this.metaContact = metaContact; } } private void initPluginComponents() { // Search for plugin components registered through the OSGI bundle // context. ServiceReference[] serRefs = null; String osgiFilter = "(" + Container.CONTAINER_ID + "=" + Container.CONTAINER_CONTACT_LIST.getID() + ")"; try { serRefs = GuiActivator.bundleContext.getServiceReferences( PluginComponentFactory.class.getName(), osgiFilter); } catch (InvalidSyntaxException exc) { logger.error("Could not obtain plugin reference.", exc); } if (serRefs != null) { for (ServiceReference serRef : serRefs) { PluginComponentFactory factory = (PluginComponentFactory) GuiActivator.bundleContext.getService(serRef); PluginComponent component = factory.getPluginComponentInstance(this); Object selectedValue = getContactList().getSelectedValue(); if (selectedValue instanceof MetaContact) { component.setCurrentContact((MetaContact) selectedValue); } else if (selectedValue instanceof MetaContactGroup) { component.setCurrentContactGroup((MetaContactGroup) selectedValue); } String pluginConstraints = factory.getConstraints(); Object constraints; if (pluginConstraints != null) constraints = UIServiceImpl.getBorderLayoutConstraintsFromContainer(pluginConstraints); else constraints = BorderLayout.SOUTH; this.add((Component) component.getComponent(), constraints); this.repaint(); } } GuiActivator.getUIService().addPluginComponentListener(this); } /** * Adds the plugin component given by <tt>event</tt> to this panel if it's its container. * * @param event the <tt>PluginComponentEvent</tt> that notified us */ public void pluginComponentAdded(PluginComponentEvent event) { PluginComponentFactory factory = event.getPluginComponentFactory(); // If the container id doesn't correspond to the id of the plugin // container we're not interested. if (!factory.getContainer().equals(Container.CONTAINER_CONTACT_LIST)) return; Object constraints = UIServiceImpl.getBorderLayoutConstraintsFromContainer(factory.getConstraints()); if (constraints == null) constraints = BorderLayout.SOUTH; PluginComponent pluginComponent = factory.getPluginComponentInstance(this); this.add((Component) pluginComponent.getComponent(), constraints); Object selectedValue = getContactList().getSelectedValue(); if (selectedValue instanceof MetaContact) { pluginComponent.setCurrentContact((MetaContact) selectedValue); } else if (selectedValue instanceof MetaContactGroup) { pluginComponent.setCurrentContactGroup((MetaContactGroup) selectedValue); } this.revalidate(); this.repaint(); } /** * Removes the plugin component given by <tt>event</tt> if previously added in this panel. * * @param event the <tt>PluginComponentEvent</tt> that notified us */ public void pluginComponentRemoved(PluginComponentEvent event) { PluginComponentFactory factory = event.getPluginComponentFactory(); // If the container id doesn't correspond to the id of the plugin // container we're not interested. if (!factory.getContainer().equals(Container.CONTAINER_CONTACT_LIST)) return; this.remove((Component) factory.getPluginComponentInstance(this).getComponent()); } }
/** * Activator for the swing notification service. * * @author Symphorien Wanko */ public class SwingNotificationActivator implements BundleActivator { /** The bundle context in which we started */ public static BundleContext bundleContext; /** A reference to the configuration service. */ private static ConfigurationService configService; /** Logger for this class. */ private static final Logger logger = Logger.getLogger(SwingNotificationActivator.class); /** A reference to the resource management service. */ private static ResourceManagementService resourcesService; /** * Start the swing notification service * * @param bc * @throws java.lang.Exception */ public void start(BundleContext bc) throws Exception { if (logger.isInfoEnabled()) logger.info("Swing Notification ...[ STARTING ]"); bundleContext = bc; PopupMessageHandler handler = null; handler = new PopupMessageHandlerSwingImpl(); getConfigurationService(); bc.registerService(PopupMessageHandler.class.getName(), handler, null); if (logger.isInfoEnabled()) logger.info("Swing Notification ...[REGISTERED]"); } public void stop(BundleContext arg0) throws Exception {} /** * Returns the <tt>ConfigurationService</tt> obtained from the bundle context. * * @return the <tt>ConfigurationService</tt> obtained from the bundle context */ public static ConfigurationService getConfigurationService() { if (configService == null) { ServiceReference configReference = bundleContext.getServiceReference(ConfigurationService.class.getName()); configService = (ConfigurationService) bundleContext.getService(configReference); } return configService; } /** * Returns the <tt>ResourceManagementService</tt> obtained from the bundle context. * * @return the <tt>ResourceManagementService</tt> obtained from the bundle context */ public static ResourceManagementService getResources() { if (resourcesService == null) resourcesService = ResourceManagementServiceUtils.getService(bundleContext); return resourcesService; } }
/** * The Dialog Class * * @author Frank Kunz The dialog class draws the basic dialog with a grid layout. The dialog * consists of three main parts. A settings panel, a table panel and three buttons. */ public final class UARTProtocolAnalysisDialog extends BaseToolDialog<UARTDataSet> implements ExportAware<UARTDataSet> { // INNER TYPES /** Provides a combobox renderer for {@link UARTParity} values. */ static final class UARTParityItemRenderer extends EnumItemRenderer<Parity> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final Parity aValue) { String text = super.getDisplayValue(aValue); if (Parity.EVEN.equals(aValue)) { text = "Even parity"; } else if (Parity.NONE.equals(aValue)) { text = "No parity"; } else if (Parity.ODD.equals(aValue)) { text = "Odd parity"; } return text; } } /** Provides a combobox renderer for {@link UARTStopBits} values. */ static final class UARTStopBitsItemRenderer extends EnumItemRenderer<StopBits> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final StopBits aValue) { String text = super.getDisplayValue(aValue); if (StopBits.ONE.equals(aValue)) { text = "1"; } else if (StopBits.ONE_HALF.equals(aValue)) { text = "1.5"; } else if (StopBits.TWO.equals(aValue)) { text = "2"; } return text; } } /** Provides a combobox renderer for {@link BitOrder} values. */ static final class UARTBitOrderItemRenderer extends EnumItemRenderer<BitOrder> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final BitOrder aValue) { String text = super.getDisplayValue(aValue); if (BitOrder.LSB_FIRST.equals(aValue)) { text = "LSB first"; } else if (BitOrder.MSB_FIRST.equals(aValue)) { text = "MSB first"; } return text; } } /** Provides a combobox renderer for {@link BitEncoding} values. */ static final class UARTBitEncodingItemRenderer extends EnumItemRenderer<BitEncoding> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final BitEncoding aValue) { String text = super.getDisplayValue(aValue); if (BitEncoding.HIGH_IS_MARK.equals(aValue)) { text = "High is mark (1)"; } else if (BitEncoding.HIGH_IS_SPACE.equals(aValue)) { text = "High is space (0)"; } return text; } } /** Provides a combobox renderer for {@link BitLevel} values. */ static final class UARTIdleLevelItemRenderer extends EnumItemRenderer<BitLevel> { // CONSTANTS private static final long serialVersionUID = 1L; // METHODS /** * @see * nl.lxtreme.ols.client.diagram.settings.GeneralSettingsDialog.EnumItemRenderer#getDisplayValue(java.lang.Enum) */ @Override protected String getDisplayValue(final BitLevel aValue) { String text = super.getDisplayValue(aValue); if (BitLevel.HIGH.equals(aValue)) { text = "High (start = L, stop = H)"; } else if (BitLevel.LOW.equals(aValue)) { text = "Low (start = H, stop = L)"; } return text; } } // CONSTANTS private static final long serialVersionUID = 1L; private static final Logger LOG = Logger.getLogger(UARTProtocolAnalysisDialog.class.getName()); // VARIABLES private JComboBox rxd; private JComboBox txd; private JComboBox cts; private JComboBox rts; private JComboBox dtr; private JComboBox dsr; private JComboBox dcd; private JComboBox ri; private JComboBox parity; private JComboBox bits; private JComboBox stop; private JComboBox bitEncoding; private JComboBox bitOrder; private JComboBox idleLevel; private JCheckBox autoDetectBaudRate; private JComboBox baudrate; private JEditorPane outText; private RestorableAction runAnalysisAction; private Action closeAction; private Action exportAction; // CONSTRUCTORS /** * Creates a new UARTProtocolAnalysisDialog instance. * * @param aOwner the owner of this dialog; * @param aToolContext the tool context; * @param aContext the OSGi bundle context to use; * @param aTool the {@link UARTAnalyser} tool. */ public UARTProtocolAnalysisDialog( final Window aOwner, final ToolContext aToolContext, final BundleContext aContext, final UARTAnalyser aTool) { super(aOwner, aToolContext, aContext, aTool); initDialog(); setLocationRelativeTo(getOwner()); } // METHODS /** {@inheritDoc} */ @Override public void exportToFile( final File aOutputFile, final nl.lxtreme.ols.tool.base.ExportAware.ExportFormat aFormat) throws IOException { if (ExportFormat.HTML.equals(aFormat)) { storeToHtmlFile(aOutputFile, getLastResult()); } else if (ExportFormat.CSV.equals(aFormat)) { storeToCsvFile(aOutputFile, getLastResult()); } } /** {@inheritDoc} */ @Override public void readPreferences(final UserSettings aSettings) { // Issue #114: avoid setting illegal values... setComboBoxIndex(this.rxd, aSettings, "rxd"); setComboBoxIndex(this.txd, aSettings, "txd"); setComboBoxIndex(this.cts, aSettings, "cts"); setComboBoxIndex(this.rts, aSettings, "rts"); setComboBoxIndex(this.dtr, aSettings, "dtr"); setComboBoxIndex(this.dsr, aSettings, "dsr"); setComboBoxIndex(this.dcd, aSettings, "dcd"); setComboBoxIndex(this.ri, aSettings, "ri"); this.parity.setSelectedIndex(aSettings.getInt("parity", this.parity.getSelectedIndex())); this.bits.setSelectedIndex(aSettings.getInt("bits", this.bits.getSelectedIndex())); this.stop.setSelectedIndex(aSettings.getInt("stop", this.stop.getSelectedIndex())); this.idleLevel.setSelectedIndex( aSettings.getInt("idle-state", this.idleLevel.getSelectedIndex())); this.bitEncoding.setSelectedIndex( aSettings.getInt("bit-encoding", this.bitEncoding.getSelectedIndex())); this.bitOrder.setSelectedIndex(aSettings.getInt("bit-order", this.bitOrder.getSelectedIndex())); this.baudrate.setSelectedItem(Integer.valueOf(aSettings.getInt("baudrate", 9600))); this.autoDetectBaudRate.setSelected( aSettings.getBoolean("auto-baudrate", this.autoDetectBaudRate.isSelected())); } /** {@inheritDoc} */ @Override public void reset() { this.outText.setText(getEmptyHtmlPage()); this.outText.setEditable(false); this.runAnalysisAction.restore(); setControlsEnabled(true); this.exportAction.setEnabled(false); } /** @see nl.lxtreme.ols.api.Configurable#writePreferences(nl.lxtreme.ols.api.UserSettings) */ @Override public void writePreferences(final UserSettings aSettings) { aSettings.putInt("rxd", this.rxd.getSelectedIndex()); aSettings.putInt("txd", this.txd.getSelectedIndex()); aSettings.putInt("cts", this.cts.getSelectedIndex()); aSettings.putInt("rts", this.rts.getSelectedIndex()); aSettings.putInt("dtr", this.dtr.getSelectedIndex()); aSettings.putInt("dsr", this.dsr.getSelectedIndex()); aSettings.putInt("dcd", this.dcd.getSelectedIndex()); aSettings.putInt("ri", this.ri.getSelectedIndex()); aSettings.putInt("parity", this.parity.getSelectedIndex()); aSettings.putInt("bits", this.bits.getSelectedIndex()); aSettings.putInt("stop", this.stop.getSelectedIndex()); aSettings.putInt("idle-state", this.idleLevel.getSelectedIndex()); aSettings.putInt("bit-encoding", this.bitEncoding.getSelectedIndex()); aSettings.putInt("bit-order", this.bitOrder.getSelectedIndex()); aSettings.putInt("baudrate", ((Integer) this.baudrate.getSelectedItem()).intValue()); aSettings.putBoolean("auto-baudrate", this.autoDetectBaudRate.isSelected()); } /** {@inheritDoc} */ @Override protected void onToolEnded(final UARTDataSet aAnalysisResult) { try { final String htmlPage; if (aAnalysisResult != null) { htmlPage = toHtmlPage(null /* aFile */, aAnalysisResult); } else { htmlPage = getEmptyHtmlPage(); } this.outText.setText(htmlPage); this.outText.setEditable(false); this.runAnalysisAction.restore(); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { // Should not happen in this situation! throw new RuntimeException(exception); } } } /** {@inheritDoc} */ @Override protected void onToolStarted() { // NO-op } /** {@inheritDoc} */ @Override protected void prepareToolTask(final ToolTask<UARTDataSet> aToolTask) { final UARTAnalyserTask toolTask = (UARTAnalyserTask) aToolTask; // The value at index zero is "Unused", so extracting one of all items // causes all "unused" values to be equivalent to -1, which is interpreted // as not used... toolTask.setRxdIndex(this.rxd.getSelectedIndex() - 1); toolTask.setTxdIndex(this.txd.getSelectedIndex() - 1); toolTask.setCtsIndex(this.cts.getSelectedIndex() - 1); toolTask.setRtsIndex(this.rts.getSelectedIndex() - 1); toolTask.setDcdIndex(this.dcd.getSelectedIndex() - 1); toolTask.setRiIndex(this.ri.getSelectedIndex() - 1); toolTask.setDsrIndex(this.dsr.getSelectedIndex() - 1); toolTask.setDtrIndex(this.dtr.getSelectedIndex() - 1); // Handle the auto detect option for baudrates... if (this.autoDetectBaudRate.isSelected()) { toolTask.setBaudRate(UARTAnalyserTask.AUTO_DETECT_BAUDRATE); } else { toolTask.setBaudRate(((Integer) this.baudrate.getSelectedItem()).intValue()); } // Other properties... toolTask.setIdleLevel((BitLevel) this.idleLevel.getSelectedItem()); toolTask.setBitEncoding((BitEncoding) this.bitEncoding.getSelectedItem()); toolTask.setBitOrder((BitOrder) this.bitOrder.getSelectedItem()); toolTask.setParity((Parity) this.parity.getSelectedItem()); toolTask.setStopBits((StopBits) this.stop.getSelectedItem()); toolTask.setBitCount(NumberUtils.smartParseInt((String) this.bits.getSelectedItem(), 8)); } /** * set the controls of the dialog enabled/disabled * * @param aEnable status of the controls */ @Override protected void setControlsEnabled(final boolean aEnable) { this.rxd.setEnabled(aEnable); this.txd.setEnabled(aEnable); this.cts.setEnabled(aEnable); this.rts.setEnabled(aEnable); this.dtr.setEnabled(aEnable); this.dsr.setEnabled(aEnable); this.dcd.setEnabled(aEnable); this.ri.setEnabled(aEnable); this.parity.setEnabled(aEnable); this.bits.setEnabled(aEnable); this.stop.setEnabled(aEnable); this.idleLevel.setEnabled(aEnable); this.bitEncoding.setEnabled(aEnable); this.bitOrder.setEnabled(aEnable); this.closeAction.setEnabled(aEnable); this.exportAction.setEnabled(aEnable); } /** * Creates the HTML template for exports to HTML. * * @param aExporter the HTML exporter instance to use, cannot be <code>null</code>. * @return a HTML exporter filled with the template, never <code>null</code>. */ private HtmlExporter createHtmlTemplate(final HtmlExporter aExporter) { aExporter.addCssStyle("body { font-family: sans-serif; } "); aExporter.addCssStyle( "table { border-width: 1px; border-spacing: 0px; border-color: gray;" + " border-collapse: collapse; border-style: solid; margin-bottom: 15px; } "); aExporter.addCssStyle( "table th { border-width: 1px; padding: 2px; border-style: solid; border-color: gray;" + " background-color: #C0C0FF; text-align: left; font-weight: bold; font-family: sans-serif; } "); aExporter.addCssStyle( "table td { border-width: 1px; padding: 2px; border-style: solid; border-color: gray;" + " font-family: monospace; } "); aExporter.addCssStyle(".error { color: red; } "); aExporter.addCssStyle(".warning { color: orange; } "); aExporter.addCssStyle(".date { text-align: right; font-size: x-small; margin-bottom: 15px; } "); aExporter.addCssStyle(".w100 { width: 100%; } "); aExporter.addCssStyle(".w35 { width: 35%; } "); aExporter.addCssStyle(".w30 { width: 30%; } "); aExporter.addCssStyle(".w15 { width: 15%; } "); aExporter.addCssStyle(".w10 { width: 10%; } "); aExporter.addCssStyle(".w8 { width: 8%; } "); aExporter.addCssStyle(".w7 { width: 7%; } "); final Element body = aExporter.getBody(); body.addChild(H1).addContent("UART Analysis results"); body.addChild(HR); body.addChild(DIV).addAttribute("class", "date").addContent("Generated: ", "{date-now}"); Element table, tr, thead, tbody; table = body.addChild(TABLE).addAttribute("class", "w100"); tbody = table.addChild(TBODY); tr = tbody.addChild(TR); tr.addChild(TH).addAttribute("colspan", "2").addContent("Statistics"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Decoded bytes"); tr.addChild(TD).addContent("{decoded-bytes}"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Detected bus errors"); tr.addChild(TD).addContent("{detected-bus-errors}"); tr = tbody.addChild(TR); tr.addChild(TD).addAttribute("class", "w30").addContent("Baudrate"); tr.addChild(TD).addContent("{baudrate}"); table = body.addChild(TABLE).addAttribute("class", "w100"); thead = table.addChild(THEAD); tr = thead.addChild(TR); tr.addChild(TH).addAttribute("class", "w30").addAttribute("colspan", "2"); tr.addChild(TH).addAttribute("class", "w35").addAttribute("colspan", "4").addContent("RxD"); tr.addChild(TH).addAttribute("class", "w35").addAttribute("colspan", "4").addContent("TxD"); tr = thead.addChild(TR); tr.addChild(TH).addAttribute("class", "w15").addContent("Index"); tr.addChild(TH).addAttribute("class", "w15").addContent("Time"); tr.addChild(TH).addAttribute("class", "w10").addContent("Hex"); tr.addChild(TH).addAttribute("class", "w10").addContent("Bin"); tr.addChild(TH).addAttribute("class", "w8").addContent("Dec"); tr.addChild(TH).addAttribute("class", "w7").addContent("ASCII"); tr.addChild(TH).addAttribute("class", "w10").addContent("Hex"); tr.addChild(TH).addAttribute("class", "w10").addContent("Bin"); tr.addChild(TH).addAttribute("class", "w8").addContent("Dec"); tr.addChild(TH).addAttribute("class", "w7").addContent("ASCII"); tbody = table.addChild(TBODY); tbody.addContent("{decoded-data}"); return aExporter; } /** @return */ private JPanel createPreviewPane() { final JPanel panTable = new JPanel(new GridLayout(1, 1, 0, 0)); this.outText = new JEditorPane("text/html", getEmptyHtmlPage()); this.outText.setEditable(false); panTable.add(new JScrollPane(this.outText)); return panTable; } /** @return */ private JPanel createSettingsPane() { final int channelCount = getData().getChannels(); final Integer[] baudrates = new Integer[AsyncSerialDataDecoder.COMMON_BAUDRATES.length]; for (int i = 0; i < baudrates.length; i++) { baudrates[i] = Integer.valueOf(AsyncSerialDataDecoder.COMMON_BAUDRATES[i]); } final String[] bitarray = new String[10]; // allow symbol lengths between 5 and 14 bits... for (int i = 0; i < bitarray.length; i++) { bitarray[i] = String.format("%d", Integer.valueOf(i + 5)); } final JPanel settings = new JPanel(new SpringLayout()); SpringLayoutUtils.addSeparator(settings, "Settings"); settings.add(createRightAlignedLabel("RxD")); this.rxd = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.rxd); settings.add(createRightAlignedLabel("TxD")); this.txd = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.txd); settings.add(createRightAlignedLabel("CTS")); this.cts = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.cts); settings.add(createRightAlignedLabel("RTS")); this.rts = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.rts); settings.add(createRightAlignedLabel("DTR")); this.dtr = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.dtr); settings.add(createRightAlignedLabel("DSR")); this.dsr = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.dsr); settings.add(createRightAlignedLabel("DCD")); this.dcd = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.dcd); settings.add(createRightAlignedLabel("RI")); this.ri = SwingComponentUtils.createOptionalChannelSelector(channelCount); settings.add(this.ri); settings.add(createRightAlignedLabel("Baudrate")); this.autoDetectBaudRate = new JCheckBox("Auto detect"); settings.add(this.autoDetectBaudRate); settings.add(new JLabel("")); this.baudrate = new JComboBox(baudrates); // Issue #90: allow custom baudrates to be specified... this.baudrate.setEditable(true); this.baudrate.setSelectedIndex(0); settings.add(this.baudrate); this.autoDetectBaudRate.addItemListener( new ItemListener() { @Override public void itemStateChanged(final ItemEvent aEvent) { final JCheckBox cb = (JCheckBox) aEvent.getSource(); UARTProtocolAnalysisDialog.this.baudrate.setEnabled(!cb.isSelected()); } }); settings.add(createRightAlignedLabel("Parity")); this.parity = new JComboBox(Parity.values()); this.parity.setSelectedIndex(0); this.parity.setRenderer(new UARTParityItemRenderer()); settings.add(this.parity); settings.add(createRightAlignedLabel("Bits")); this.bits = new JComboBox(bitarray); this.bits.setSelectedIndex(3); settings.add(this.bits); settings.add(createRightAlignedLabel("Stopbits")); this.stop = new JComboBox(StopBits.values()); this.stop.setSelectedIndex(0); this.stop.setRenderer(new UARTStopBitsItemRenderer()); settings.add(this.stop); settings.add(createRightAlignedLabel("Idle level")); this.idleLevel = new JComboBox(BitLevel.values()); this.idleLevel.setSelectedIndex(0); this.idleLevel.setRenderer(new UARTIdleLevelItemRenderer()); settings.add(this.idleLevel); settings.add(createRightAlignedLabel("Bit encoding")); this.bitEncoding = new JComboBox(BitEncoding.values()); this.bitEncoding.setSelectedIndex(0); this.bitEncoding.setRenderer(new UARTBitEncodingItemRenderer()); settings.add(this.bitEncoding); settings.add(createRightAlignedLabel("Bit order")); this.bitOrder = new JComboBox(BitOrder.values()); this.bitOrder.setSelectedIndex(0); this.bitOrder.setRenderer(new UARTBitOrderItemRenderer()); settings.add(this.bitOrder); SpringLayoutUtils.makeEditorGrid(settings, 10, 4); return settings; } /** * generate a HTML page * * @param empty if this is true an empty output is generated * @return String with HTML data */ private String getEmptyHtmlPage() { final HtmlExporter exporter = createHtmlTemplate(ExportUtils.createHtmlExporter()); return exporter.toString( new MacroResolver() { @Override public Object resolve(final String aMacro, final Element aParent) { if ("date-now".equals(aMacro)) { final DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); return df.format(new Date()); } else if ("decoded-bytes".equals(aMacro) || "detected-bus-errors".equals(aMacro) || "baudrate".equals(aMacro)) { return "-"; } else if ("decoded-data".equals(aMacro)) { return null; } return null; } }); } /** Initializes this dialog. */ private void initDialog() { setMinimumSize(new Dimension(640, 480)); final JComponent settingsPane = createSettingsPane(); final JComponent previewPane = createPreviewPane(); final JPanel contentPane = new JPanel(new GridBagLayout()); contentPane.add( settingsPane, new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(2, 0, 2, 0), 0, 0)); contentPane.add( previewPane, new GridBagConstraints( 1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(2, 0, 2, 0), 0, 0)); final JButton runAnalysisButton = ToolUtils.createRunAnalysisButton(this); this.runAnalysisAction = (RestorableAction) runAnalysisButton.getAction(); final JButton exportButton = ToolUtils.createExportButton(this); this.exportAction = exportButton.getAction(); this.exportAction.setEnabled(false); final JButton closeButton = ToolUtils.createCloseButton(); this.closeAction = closeButton.getAction(); final JComponent buttons = SwingComponentUtils.createButtonPane(runAnalysisButton, exportButton, closeButton); SwingComponentUtils.setupWindowContentPane(this, contentPane, buttons, runAnalysisButton); } /** * exports the data to a CSV file * * @param aFile File object */ private void storeToCsvFile(final File aFile, final UARTDataSet aDataSet) { try { final CsvExporter exporter = ExportUtils.createCsvExporter(aFile); exporter.setHeaders( "index", "start-time", "end-time", "event?", "event-type", "RxD event", "TxD event", "RxD data", "TxD data"); final List<UARTData> decodedData = aDataSet.getData(); for (int i = 0; i < decodedData.size(); i++) { final UARTData ds = decodedData.get(i); final String startTime = Unit.Time.format(aDataSet.getTime(ds.getStartSampleIndex())); final String endTime = Unit.Time.format(aDataSet.getTime(ds.getEndSampleIndex())); String eventType = null; String rxdEvent = null; String txdEvent = null; String rxdData = null; String txdData = null; switch (ds.getType()) { case UARTData.UART_TYPE_EVENT: eventType = ds.getEventName(); break; case UARTData.UART_TYPE_RXEVENT: rxdEvent = ds.getEventName(); break; case UARTData.UART_TYPE_TXEVENT: txdEvent = ds.getEventName(); break; case UARTData.UART_TYPE_RXDATA: rxdData = Integer.toString(ds.getData()); break; case UARTData.UART_TYPE_TXDATA: txdData = Integer.toString(ds.getData()); break; default: break; } exporter.addRow( Integer.valueOf(i), startTime, endTime, Boolean.valueOf(ds.isEvent()), eventType, rxdEvent, txdEvent, rxdData, txdData); } exporter.close(); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { LOG.log(Level.WARNING, "CSV export failed!", exception); } } } /** * stores the data to a HTML file * * @param aFile file object */ private void storeToHtmlFile(final File aFile, final UARTDataSet aDataSet) { try { toHtmlPage(aFile, aDataSet); } catch (final IOException exception) { // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { LOG.log(Level.WARNING, "HTML export failed!", exception); } } } /** * generate a HTML page * * @param empty if this is true an empty output is generated * @return String with HTML data */ private String toHtmlPage(final File aFile, final UARTDataSet aDataSet) throws IOException { final int bitCount = Integer.parseInt((String) this.bits.getSelectedItem()); final int bitAdder = ((bitCount % 4) != 0) ? 1 : 0; final MacroResolver macroResolver = new MacroResolver() { @Override public Object resolve(final String aMacro, final Element aParent) { if ("date-now".equals(aMacro)) { final DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); return df.format(new Date()); } else if ("decoded-bytes".equals(aMacro)) { return Integer.valueOf(aDataSet.getDecodedSymbols()); } else if ("detected-bus-errors".equals(aMacro)) { return Integer.valueOf(aDataSet.getDetectedErrors()); } else if ("baudrate".equals(aMacro)) { final String baudrate; if (aDataSet.getBaudRate() <= 0) { baudrate = "<span class='error'>Baudrate calculation failed!</span>"; } else { baudrate = String.format( "%d (exact: %d)", Integer.valueOf(aDataSet.getBaudRate()), Integer.valueOf(aDataSet.getBaudRateExact())); if (!aDataSet.isBitLengthUsable()) { return baudrate.concat( " <span class='warning'>The baudrate may be wrong, use a higher samplerate to avoid this!</span>"); } return baudrate; } } else if ("decoded-data".equals(aMacro)) { final List<UARTData> decodedData = aDataSet.getData(); Element tr; for (int i = 0; i < decodedData.size(); i++) { final UARTData ds = decodedData.get(i); if (ds.isEvent()) { String rxEventData = ""; String txEventData = ""; String bgColor; if (UARTData.UART_TYPE_EVENT == ds.getType()) { rxEventData = txEventData = ds.getEventName(); bgColor = "#e0e0e0"; } else if (UARTData.UART_TYPE_RXEVENT == ds.getType()) { rxEventData = ds.getEventName(); bgColor = "#c0ffc0"; } else if (UARTData.UART_TYPE_TXEVENT == ds.getType()) { txEventData = ds.getEventName(); bgColor = "#c0ffc0"; } else { // unknown event bgColor = "#ff8000"; } if (txEventData.endsWith("_ERR") || rxEventData.endsWith("_ERR")) { bgColor = "#ff8000"; } tr = aParent .addChild(TR) .addAttribute("style", "background-color: " + bgColor + ";"); tr.addChild(TD).addContent(String.valueOf(i)); tr.addChild(TD) .addContent(Unit.Time.format(aDataSet.getTime(ds.getStartSampleIndex()))); tr.addChild(TD).addContent(rxEventData); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD).addContent(txEventData); tr.addChild(TD); tr.addChild(TD); tr.addChild(TD); } else { String rxDataHex = "", rxDataBin = "", rxDataDec = "", rxDataASCII = ""; String txDataHex = "", txDataBin = "", txDataDec = "", txDataASCII = ""; // Normal data... if (UARTData.UART_TYPE_RXDATA == ds.getType()) { final int rxData = ds.getData(); rxDataHex = integerToHexString(rxData, (bitCount / 4) + bitAdder); rxDataBin = integerToBinString(rxData, bitCount); rxDataDec = String.valueOf(rxData); rxDataASCII = toASCII((char) rxData); } else /* if ( UARTData.UART_TYPE_TXDATA == ds.getType() ) */ { final int txData = ds.getData(); txDataHex = integerToHexString(txData, (bitCount / 4) + bitAdder); txDataBin = integerToBinString(txData, bitCount); txDataDec = String.valueOf(txData); txDataASCII = toASCII(txData); } tr = aParent.addChild(TR); tr.addChild(TD).addContent(String.valueOf(i)); tr.addChild(TD) .addContent(Unit.Time.format(aDataSet.getTime(ds.getStartSampleIndex()))); tr.addChild(TD).addContent("0x", rxDataHex); tr.addChild(TD).addContent("0b", rxDataBin); tr.addChild(TD).addContent(rxDataDec); tr.addChild(TD).addContent(rxDataASCII); tr.addChild(TD).addContent("0x", txDataHex); tr.addChild(TD).addContent("0b", txDataBin); tr.addChild(TD).addContent(txDataDec); tr.addChild(TD).addContent(txDataASCII); } } } return null; } }; if (aFile == null) { final HtmlExporter exporter = createHtmlTemplate(ExportUtils.createHtmlExporter()); return exporter.toString(macroResolver); } else { final HtmlFileExporter exporter = (HtmlFileExporter) createHtmlTemplate(ExportUtils.createHtmlExporter(aFile)); exporter.write(macroResolver); exporter.close(); } return null; } }
/** * Tests whether accaounts are uninstalled properly. It is important that tests from this class be * called last since they will install the accounts that have been used to test the implementations. * Apart from uninstallation tests the class also contains tests that remove and reinstall the * protocol provider bundle in order to verify that accounts are persistent. * * @author Emil Ivov */ public class TestAccountUninstallation extends TestCase { private static final Logger logger = Logger.getLogger(TestAccountUninstallation.class); private SipSlickFixture fixture = new SipSlickFixture(); /** * Constructs a test instance * * @param name The name of the test. */ public TestAccountUninstallation(String name) { super(name); } /** * JUnit setup method. * * @throws Exception in case anything goes wrong. */ protected void setUp() throws Exception { super.setUp(); fixture.setUp(); } /** * JUnit teardown method. * * @throws Exception in case anything goes wrong. */ protected void tearDown() throws Exception { fixture.tearDown(); super.tearDown(); } /** * Returns a suite containing tests in this class in the order that we'd like them executed. * * @return a Test suite containing tests in this class in the order that we'd like them executed. */ public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(new TestAccountUninstallation("testProviderUnregister")); suite.addTest(new TestAccountUninstallation("testInstallationPersistency")); suite.addTest(new TestAccountUninstallation("testUninstallAccount")); return suite; } /** * Unregisters both providers and verifies whether they have changed state accordingly. * * @throws OperationFailedException if unregister fails with an error. */ public void testProviderUnregister() throws OperationFailedException { // make sure providers are still registered assertEquals(fixture.provider1.getRegistrationState(), RegistrationState.REGISTERED); assertEquals(fixture.provider2.getRegistrationState(), RegistrationState.REGISTERED); UnregistrationEventCollector collector1 = new UnregistrationEventCollector(); UnregistrationEventCollector collector2 = new UnregistrationEventCollector(); fixture.provider1.addRegistrationStateChangeListener(collector1); fixture.provider2.addRegistrationStateChangeListener(collector2); // unregister both providers fixture.provider1.unregister(); fixture.provider2.unregister(); collector1.waitForEvent(10000); collector2.waitForEvent(10000); assertTrue( "Provider did not distribute unregister events", 2 <= collector1.collectedNewStates.size()); assertTrue( "Provider did not distribute unregister events", 2 <= collector2.collectedNewStates.size()); // make sure both providers are now unregistered. assertEquals( "Provider state after calling unregister().", RegistrationState.UNREGISTERED, fixture.provider1.getRegistrationState()); assertEquals( "Provider state after calling unregister().", RegistrationState.UNREGISTERED, fixture.provider2.getRegistrationState()); } /** * Stops and removes the tested bundle, verifies that it has unregistered its provider, then * reloads and restarts the bundle and verifies that the protocol provider is reRegistered in the * bundle context. * * @throws java.lang.Exception if an exception occurs during testing. */ public void testInstallationPersistency() throws Exception { Bundle providerBundle = fixture.findProtocolProviderBundle(fixture.provider1); // set the global providerBundle reference that we will be using // in the last series of tests (Account uninstallation persistency) SipSlickFixture.providerBundle = providerBundle; assertNotNull("Couldn't find a bundle for the tested provider", providerBundle); providerBundle.stop(); assertTrue( "Couldn't stop the protocol provider bundle. State was " + providerBundle.getState(), Bundle.ACTIVE != providerBundle.getState() && Bundle.STOPPING != providerBundle.getState()); providerBundle.uninstall(); assertEquals( "Couldn't stop the protocol provider bundle.", Bundle.UNINSTALLED, providerBundle.getState()); // verify that the provider is no longer available ServiceReference[] sipProviderRefs = null; try { sipProviderRefs = fixture.bc.getServiceReferences( ProtocolProviderService.class.getName(), "(&" + "(" + ProtocolProviderFactory.PROTOCOL + "=" + ProtocolNames.SIP + ")" + "(" + ProtocolProviderFactory.USER_ID + "=" + fixture.userID1 + ")" + ")"); } catch (InvalidSyntaxException ex) { fail("We apparently got our filter wrong: " + ex.getMessage()); } // make sure we didn't see a service assertTrue( "A Protocol Provider Service was still regged as an osgi service " + "for SIP URI:" + fixture.userID1 + "After it was explicitly uninstalled", sipProviderRefs == null || sipProviderRefs.length == 0); // verify that the provider factory knows that we have uninstalled the // provider. assertTrue( "The SIP provider factory kept a reference to the provider we just " + "uninstalled (uri=" + fixture.userID1 + ")", fixture.providerFactory.getRegisteredAccounts().isEmpty() && fixture.providerFactory.getProviderForAccount(fixture.provider1.getAccountID()) == null); // Now reinstall the bundle providerBundle = fixture.bc.installBundle(providerBundle.getLocation()); // set the global providerBundle reference that we will be using // in the last series of tests (Account uninstallation persistency) SipSlickFixture.providerBundle = providerBundle; assertEquals( "Couldn't re-install protocol provider bundle.", Bundle.INSTALLED, providerBundle.getState()); AccountManagerUtils.startBundleAndWaitStoredAccountsLoaded( fixture.bc, providerBundle, ProtocolNames.SIP); assertEquals( "Couldn't re-start protocol provider bundle.", Bundle.ACTIVE, providerBundle.getState()); // Make sure that the provider is there again. // verify that the provider is no longer available try { sipProviderRefs = fixture.bc.getServiceReferences( ProtocolProviderService.class.getName(), "(&" + "(" + ProtocolProviderFactory.PROTOCOL + "=" + ProtocolNames.SIP + ")" + "(" + ProtocolProviderFactory.USER_ID + "=" + fixture.userID1 + ")" + ")"); } catch (InvalidSyntaxException ex) { fail("We apparently got our filter wrong " + ex.getMessage()); } // make sure we didn't see a service assertTrue( "A Protocol Provider Service was not restored after being" + "reinstalled. SIP URI:" + fixture.userID1, sipProviderRefs != null && sipProviderRefs.length > 0); ServiceReference[] sipFactoryRefs = null; try { sipFactoryRefs = fixture.bc.getServiceReferences( ProtocolProviderFactory.class.getName(), "(" + ProtocolProviderFactory.PROTOCOL + "=" + ProtocolNames.SIP + ")"); } catch (InvalidSyntaxException ex) { fail("We apparently got our filter wrong " + ex.getMessage()); } // we're the ones who've reinstalled the factory so it's our // responsibility to update the fixture. fixture.providerFactory = (ProtocolProviderFactory) fixture.bc.getService(sipFactoryRefs[0]); fixture.provider1 = (ProtocolProviderService) fixture.bc.getService(sipProviderRefs[0]); // verify that the provider is also restored in the provider factory // itself assertTrue( "The SIP provider did not restore its own reference to the provider " + "that we just reinstalled (URI=" + fixture.userID1 + ")", !fixture.providerFactory.getRegisteredAccounts().isEmpty() && fixture.providerFactory.getProviderForAccount(fixture.provider1.getAccountID()) != null); } /** Uinstalls our test account and makes sure it really has been removed. */ public void testUninstallAccount() { assertFalse( "No installed accounts found", fixture.providerFactory.getRegisteredAccounts().isEmpty()); assertNotNull( "Found no provider corresponding to URI " + fixture.userID1, fixture.providerFactory.getProviderForAccount(fixture.provider1.getAccountID())); assertTrue( "Failed to remove a provider corresponding to URI " + fixture.userID1, fixture.providerFactory.uninstallAccount(fixture.provider1.getAccountID())); assertTrue( "Failed to remove a provider corresponding to URI " + fixture.userID1, fixture.providerFactory.uninstallAccount(fixture.provider2.getAccountID())); // make sure no providers have remained installed. ServiceReference[] sipProviderRefs = null; try { sipProviderRefs = fixture.bc.getServiceReferences( ProtocolProviderService.class.getName(), "(" + ProtocolProviderFactory.PROTOCOL + "=" + ProtocolNames.SIP + ")"); } catch (InvalidSyntaxException ex) { fail("We apparently got our filter wrong " + ex.getMessage()); } // make sure we didn't see a service assertTrue( "A Protocol Provider Service was still regged as an osgi " + "service for SIP URI:" + fixture.userID1 + "After it was explicitly uninstalled", sipProviderRefs == null || sipProviderRefs.length == 0); // verify that the provider factory knows that we have uninstalled the // provider. assertTrue( "The SIP provider factory kept a reference to the provider we just " + "uninstalled (uri=" + fixture.userID1 + ")", fixture.providerFactory.getRegisteredAccounts().isEmpty() && fixture.providerFactory.getProviderForAccount(fixture.provider1.getAccountID()) == null); } /** * A class that would plugin as a registration listener to a protocol provider and simply record * all events that it sees and notifyAll() if it sees an event that notifies us of a completed * registration. */ public class UnregistrationEventCollector implements RegistrationStateChangeListener { public List<RegistrationState> collectedNewStates = new LinkedList<RegistrationState>(); /** * The method would simply register all received events so that they could be available for * later inspection by the unit tests. In the case where a registraiton event notifying us of a * completed registration is seen, the method would call notifyAll(). * * @param evt ProviderStatusChangeEvent the event describing the status change. */ public void registrationStateChanged(RegistrationStateChangeEvent evt) { logger.debug("Received a RegistrationStateChangeEvent: " + evt); collectedNewStates.add(evt.getNewState()); if (evt.getNewState().equals(RegistrationState.UNREGISTERED)) { logger.debug("We're registered and will notify those who wait"); synchronized (this) { notifyAll(); } } } /** * Blocks until an event notifying us of the awaited state change is received or until waitFor * miliseconds pass (whichever happens first). * * @param waitFor the number of miliseconds that we should be waiting for an event before simply * bailing out. */ public void waitForEvent(long waitFor) { logger.trace("Waiting for a RegistrationStateChangeEvent"); synchronized (this) { if (collectedNewStates.contains(RegistrationState.UNREGISTERED)) { logger.trace("Event already received. " + collectedNewStates); return; } try { wait(waitFor); if (collectedNewStates.size() > 0) logger.trace("Received a RegistrationStateChangeEvent."); else logger.trace("No RegistrationStateChangeEvent received for " + waitFor + "ms."); } catch (InterruptedException ex) { logger.debug("Interrupted while waiting for a " + "RegistrationStateChangeEvent", ex); } } } } }
/** * The advanced configuration panel. * * @author Yana Stamcheva */ public class AdvancedConfigurationPanel extends TransparentPanel implements ConfigurationForm, ConfigurationContainer, ServiceListener, ListSelectionListener { /** Serial version UID. */ private static final long serialVersionUID = 0L; /** The <tt>Logger</tt> used by this <tt>AdvancedConfigurationPanel</tt> for logging output. */ private final Logger logger = Logger.getLogger(AdvancedConfigurationPanel.class); /** The configuration list. */ private final JList configList = new JList(); /** The center panel. */ private final JPanel centerPanel = new TransparentPanel(new BorderLayout()); /** Creates an instance of the <tt>AdvancedConfigurationPanel</tt>. */ public AdvancedConfigurationPanel() { super(new BorderLayout(10, 0)); initList(); centerPanel.setPreferredSize(new Dimension(500, 500)); add(centerPanel, BorderLayout.CENTER); } /** Initializes the config list. */ private void initList() { configList.setModel(new DefaultListModel()); configList.setCellRenderer(new ConfigListCellRenderer()); configList.addListSelectionListener(this); configList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); JScrollPane configScrollList = new JScrollPane(); configScrollList.getVerticalScrollBar().setUnitIncrement(30); configScrollList.getViewport().add(configList); add(configScrollList, BorderLayout.WEST); String osgiFilter = "(" + ConfigurationForm.FORM_TYPE + "=" + ConfigurationForm.ADVANCED_TYPE + ")"; ServiceReference[] confFormsRefs = null; try { confFormsRefs = AdvancedConfigActivator.bundleContext.getServiceReferences( ConfigurationForm.class.getName(), osgiFilter); } catch (InvalidSyntaxException ex) { } if (confFormsRefs != null) { for (int i = 0; i < confFormsRefs.length; i++) { ConfigurationForm form = (ConfigurationForm) AdvancedConfigActivator.bundleContext.getService(confFormsRefs[i]); if (form.isAdvanced()) this.addConfigForm(form); } } } /** * Shows on the right the configuration form given by the given <tt>ConfigFormDescriptor</tt>. * * @param configForm the configuration form to show */ private void showFormContent(ConfigurationForm configForm) { this.centerPanel.removeAll(); JComponent configFormPanel = (JComponent) configForm.getForm(); configFormPanel.setOpaque(false); this.centerPanel.add(configFormPanel, BorderLayout.CENTER); this.centerPanel.revalidate(); this.centerPanel.repaint(); } /** * Handles registration of a new configuration form. * * @param event the <tt>ServiceEvent</tt> that notified us */ public void serviceChanged(ServiceEvent event) { Object sService = AdvancedConfigActivator.bundleContext.getService(event.getServiceReference()); // we don't care if the source service is not a configuration form if (!(sService instanceof ConfigurationForm)) return; ConfigurationForm configForm = (ConfigurationForm) sService; /* * This AdvancedConfigurationPanel is an advanced ConfigurationForm so * don't try to add it to itself. */ if ((configForm == this) || !configForm.isAdvanced()) return; switch (event.getType()) { case ServiceEvent.REGISTERED: if (logger.isInfoEnabled()) logger.info("Handling registration of a new Configuration Form."); this.addConfigForm(configForm); break; case ServiceEvent.UNREGISTERING: this.removeConfigForm(configForm); break; } } /** * Adds a new <tt>ConfigurationForm</tt> to this list. * * @param configForm The <tt>ConfigurationForm</tt> to add. */ public void addConfigForm(ConfigurationForm configForm) { if (configForm == null) throw new IllegalArgumentException("configForm"); DefaultListModel listModel = (DefaultListModel) configList.getModel(); int i = 0; int count = listModel.getSize(); int configFormIndex = configForm.getIndex(); for (; i < count; i++) { ConfigurationForm form = (ConfigurationForm) listModel.get(i); if (configFormIndex < form.getIndex()) break; } listModel.add(i, configForm); } /** * Implements <code>ApplicationWindow.show</code> method. * * @param isVisible specifies whether the frame is to be visible or not. */ @Override public void setVisible(boolean isVisible) { if (isVisible && configList.getSelectedIndex() < 0) { this.configList.setSelectedIndex(0); } super.setVisible(isVisible); } /** * Removes a <tt>ConfigurationForm</tt> from this list. * * @param configForm The <tt>ConfigurationForm</tt> to remove. */ public void removeConfigForm(ConfigurationForm configForm) { DefaultListModel listModel = (DefaultListModel) configList.getModel(); for (int count = listModel.getSize(), i = count - 1; i >= 0; i--) { ConfigurationForm form = (ConfigurationForm) listModel.get(i); if (form.equals(configForm)) { listModel.remove(i); /* * TODO We may just consider not allowing duplicates on addition * and then break here. */ } } } /** A custom cell renderer that represents a <tt>ConfigurationForm</tt>. */ private class ConfigListCellRenderer extends DefaultListCellRenderer { /** Serial version UID. */ private static final long serialVersionUID = 0L; private boolean isSelected = false; private final Color selectedColor = new Color( AdvancedConfigActivator.getResources().getColor("service.gui.LIST_SELECTION_COLOR")); /** * Creates an instance of <tt>ConfigListCellRenderer</tt> and specifies that this renderer is * transparent. */ public ConfigListCellRenderer() { this.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); this.setOpaque(false); } /** * Returns the component representing the cell given by parameters. * * @param list the parent list * @param value the value of the cell * @param index the index of the cell * @param isSelected indicates if the cell is selected * @param cellHasFocus indicates if the cell has the focus * @return the component representing the cell */ public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { ConfigurationForm configForm = (ConfigurationForm) value; this.isSelected = isSelected; this.setText(configForm.getTitle()); return this; } /** * Paint a background for all groups and a round blue border and background when a cell is * selected. * * @param g the <tt>Graphics</tt> object */ public void paintComponent(Graphics g) { Graphics g2 = g.create(); try { internalPaintComponent(g2); } finally { g2.dispose(); } super.paintComponent(g); } /** * Paint a background for all groups and a round blue border and background when a cell is * selected. * * @param g the <tt>Graphics</tt> object */ private void internalPaintComponent(Graphics g) { AntialiasingManager.activateAntialiasing(g); Graphics2D g2 = (Graphics2D) g; if (isSelected) { g2.setColor(selectedColor); g2.fillRect(0, 0, this.getWidth(), this.getHeight()); } } } /** * Called when user selects a component in the list of configuration forms. * * @param e the <tt>ListSelectionEvent</tt> */ public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { ConfigurationForm configForm = (ConfigurationForm) configList.getSelectedValue(); if (configForm != null) showFormContent(configForm); } } /** * Selects the given <tt>ConfigurationForm</tt>. * * @param configForm the <tt>ConfigurationForm</tt> to select */ public void setSelected(ConfigurationForm configForm) { configList.setSelectedValue(configForm, true); } /** * Returns the title of the form. * * @return the title of the form */ public String getTitle() { return AdvancedConfigActivator.getResources().getI18NString("service.gui.ADVANCED"); } /** * Returns the icon of the form. * * @return a byte array containing the icon of the form */ public byte[] getIcon() { return AdvancedConfigActivator.getResources() .getImageInBytes("plugin.advancedconfig.PLUGIN_ICON"); } /** * Returns the form component. * * @return the form component */ public Object getForm() { return this; } /** * Returns the index of the form in its parent container. * * @return the index of the form in its parent container */ public int getIndex() { return 300; } /** * Indicates if the form is an advanced form. * * @return <tt>true</tt> to indicate that this is an advanced form, otherwise returns * <tt>false</tt> */ public boolean isAdvanced() { return false; } /** * Validates the currently selected configuration form. This method is meant to be used by * configuration forms the re-validate when a new component has been added or size has changed. */ public void validateCurrentForm() {} }
/** * The <tt>StatusSubMenu</tt> provides a menu which allow to select the status for each of the * protocol providers registered when the menu appears * * @author Nicolas Chamouard */ public class StatusSubMenu extends JMenu { /** A reference of <tt>Systray</tt> */ private SystrayServiceJdicImpl parentSystray; /** Contains all accounts and corresponding menus. */ private Hashtable accountSelectors = new Hashtable(); private Logger logger = Logger.getLogger(StatusSubMenu.class); /** * Creates an instance of <tt>StatusSubMenu</tt>. * * @param tray a reference of the parent <tt>Systray</tt> */ public StatusSubMenu(SystrayServiceJdicImpl tray) { parentSystray = tray; this.setText(Resources.getString("setStatus")); this.setIcon(Resources.getImage("statusMenuIcon")); /* makes the menu look better */ this.setPreferredSize(new java.awt.Dimension(28, 24)); this.init(); } /** * Adds the account corresponding to the given protocol provider to this menu. * * @param protocolProvider the protocol provider corresponding to the account to add */ private void addAccount(ProtocolProviderService protocolProvider) { OperationSetPresence presence = (OperationSetPresence) protocolProvider.getOperationSet(OperationSetPresence.class); if (presence == null) { StatusSimpleSelector simpleSelector = new StatusSimpleSelector(parentSystray, protocolProvider); this.accountSelectors.put(protocolProvider.getAccountID(), simpleSelector); this.add(simpleSelector); } else { StatusSelector statusSelector = new StatusSelector(parentSystray, protocolProvider, presence); this.accountSelectors.put(protocolProvider.getAccountID(), statusSelector); this.add(statusSelector); presence.addProviderPresenceStatusListener(new SystrayProviderPresenceStatusListener()); } } /** * Removes the account corresponding to the given protocol provider from this menu. * * @param protocolProvider the protocol provider corresponding to the account to remove. */ private void removeAccount(ProtocolProviderService protocolProvider) { Component c = (Component) this.accountSelectors.get(protocolProvider.getAccountID()); this.remove(c); } /** * We fill the protocolProviderTable with all running protocol providers at the start of the * bundle. */ private void init() { SystrayActivator.bundleContext.addServiceListener(new ProtocolProviderServiceListener()); ServiceReference[] protocolProviderRefs = null; try { protocolProviderRefs = SystrayActivator.bundleContext.getServiceReferences( ProtocolProviderService.class.getName(), null); } catch (InvalidSyntaxException ex) { // this shouldn't happen since we're providing no parameter string // but let's log just in case. logger.error("Error while retrieving service refs", ex); return; } // in case we found any if (protocolProviderRefs != null) { for (int i = 0; i < protocolProviderRefs.length; i++) { ProtocolProviderService provider = (ProtocolProviderService) SystrayActivator.bundleContext.getService(protocolProviderRefs[i]); boolean isHidden = provider.getAccountID().getAccountProperties().get("HIDDEN_PROTOCOL") != null; if (!isHidden) this.addAccount(provider); } } } /** * Listens for <tt>ServiceEvent</tt>s indicating that a <tt>ProtocolProviderService</tt> has been * registered and completes the account status menu. */ private class ProtocolProviderServiceListener implements ServiceListener { /** * When a service is registered or unregistered, we update the provider tables and add/remove * listeners (if it supports BasicInstantMessenging implementation) * * @param event ServiceEvent */ public void serviceChanged(ServiceEvent event) { // if the event is caused by a bundle being stopped, we don't want to // know if (event.getServiceReference().getBundle().getState() == Bundle.STOPPING) { return; } Object service = SystrayActivator.bundleContext.getService(event.getServiceReference()); if (!(service instanceof ProtocolProviderService)) return; ProtocolProviderService provider = (ProtocolProviderService) service; if (event.getType() == ServiceEvent.REGISTERED) addAccount(provider); if (event.getType() == ServiceEvent.UNREGISTERING) removeAccount(provider); } } /** * Listens for all providerStatusChanged and providerStatusMessageChanged events in order to * refresh the account status panel, when a status is changed. */ private class SystrayProviderPresenceStatusListener implements ProviderPresenceStatusListener { /** Fired when an account has changed its status. We update the icon in the menu. */ public void providerStatusChanged(ProviderPresenceStatusChangeEvent evt) { ProtocolProviderService pps = evt.getProvider(); StatusSelector selectorBox = (StatusSelector) accountSelectors.get(pps.getAccountID()); if (selectorBox == null) return; selectorBox.updateStatus(evt.getNewStatus()); } public void providerStatusMessageChanged(PropertyChangeEvent evt) {} } }
/** Denotes a front-end controller for the client. */ public final class ClientController implements ActionProvider, CaptureCallback, AnalysisCallback { // INNER TYPES /** Provides a default tool context implementation. */ static final class DefaultToolContext implements ToolContext { // VARIABLES private final int startSampleIdx; private final int endSampleIdx; // CONSTRUCTORS /** * Creates a new DefaultToolContext instance. * * @param aStartSampleIdx the starting sample index; * @param aEndSampleIdx the ending sample index. */ public DefaultToolContext(final int aStartSampleIdx, final int aEndSampleIdx) { this.startSampleIdx = aStartSampleIdx; this.endSampleIdx = aEndSampleIdx; } /** @see nl.lxtreme.ols.api.tools.ToolContext#getEndSampleIndex() */ @Override public int getEndSampleIndex() { return this.endSampleIdx; } /** @see nl.lxtreme.ols.api.tools.ToolContext#getLength() */ @Override public int getLength() { return Math.max(0, this.endSampleIdx - this.startSampleIdx); } /** @see nl.lxtreme.ols.api.tools.ToolContext#getStartSampleIndex() */ @Override public int getStartSampleIndex() { return this.startSampleIdx; } } // CONSTANTS private static final Logger LOG = Logger.getLogger(ClientController.class.getName()); // VARIABLES private final ActionManager actionManager; private final BundleContext bundleContext; private final DataContainer dataContainer; private final EventListenerList evenListeners; private final ProjectManager projectManager; private final Host host; private MainFrame mainFrame; private volatile DeviceController currentDevCtrl; // CONSTRUCTORS /** Creates a new ClientController instance. */ public ClientController( final BundleContext aBundleContext, final Host aHost, final ProjectManager aProjectManager) { this.bundleContext = aBundleContext; this.host = aHost; this.projectManager = aProjectManager; this.dataContainer = new DataContainer(this.projectManager); this.actionManager = new ActionManager(); this.evenListeners = new EventListenerList(); fillActionManager(this.actionManager); } // METHODS /** * Adds a cursor change listener. * * @param aListener the listener to add, cannot be <code>null</code>. */ public void addCursorChangeListener(final DiagramCursorChangeListener aListener) { this.evenListeners.add(DiagramCursorChangeListener.class, aListener); } /** * Adds the given device controller to this controller. * * @param aDeviceController the device controller to add, cannot be <code>null</code>. */ public void addDevice(final DeviceController aDeviceController) { if (this.mainFrame != null) { if (this.mainFrame.addDeviceMenuItem(aDeviceController)) { this.currentDevCtrl = aDeviceController; } } updateActions(); } /** * Adds the given exporter to this controller. * * @param aExporter the exporter to add, cannot be <code>null</code>. */ public void addExporter(final Exporter aExporter) { if (this.mainFrame != null) { this.mainFrame.addExportMenuItem(aExporter.getName()); } updateActions(); } /** * Adds the given tool to this controller. * * @param aTool the tool to add, cannot be <code>null</code>. */ public void addTool(final Tool aTool) { if (this.mainFrame != null) { this.mainFrame.addToolMenuItem(aTool.getName()); } updateActions(); } /** @see nl.lxtreme.ols.api.tools.AnalysisCallback#analysisAborted(java.lang.String) */ @Override public void analysisAborted(final String aReason) { setStatus("Analysis aborted! " + aReason); updateActions(); } /** * @see * nl.lxtreme.ols.api.tools.AnalysisCallback#analysisComplete(nl.lxtreme.ols.api.data.CapturedData) */ @Override public void analysisComplete(final CapturedData aNewCapturedData) { if (aNewCapturedData != null) { this.dataContainer.setCapturedData(aNewCapturedData); } if (this.mainFrame != null) { repaintMainFrame(); } setStatus(""); updateActions(); } /** Cancels the current capturing (if in progress). */ public void cancelCapture() { final DeviceController deviceController = getDeviceController(); if (deviceController == null) { return; } deviceController.cancel(); } /** @see nl.lxtreme.ols.api.devices.CaptureCallback#captureAborted(java.lang.String) */ @Override public void captureAborted(final String aReason) { setStatus("Capture aborted! " + aReason); updateActions(); } /** * @see * nl.lxtreme.ols.api.devices.CaptureCallback#captureComplete(nl.lxtreme.ols.api.data.CapturedData) */ @Override public void captureComplete(final CapturedData aCapturedData) { setCapturedData(aCapturedData); setStatus("Capture finished at {0,date,medium} {0,time,medium}.", new Date()); updateActions(); } /** * Captures the data of the current device controller. * * @param aParent the parent window to use, can be <code>null</code>. * @return <code>true</code> if the capture succeeded, <code>false</code> otherwise. * @throws IOException in case of I/O problems. */ public boolean captureData(final Window aParent) { final DeviceController devCtrl = getDeviceController(); if (devCtrl == null) { return false; } try { if (devCtrl.setupCapture(aParent)) { setStatus( "Capture from {0} started at {1,date,medium} {1,time,medium} ...", devCtrl.getName(), new Date()); devCtrl.captureData(this); return true; } return false; } catch (IOException exception) { captureAborted("I/O problem: " + exception.getMessage()); // Make sure to handle IO-interrupted exceptions properly! if (!HostUtils.handleInterruptedException(exception)) { exception.printStackTrace(); } return false; } finally { updateActions(); } } /** @see nl.lxtreme.ols.api.devices.CaptureCallback#captureStarted(int, int, int) */ @Override public synchronized void captureStarted( final int aSampleRate, final int aChannelCount, final int aChannelMask) { final Runnable runner = new Runnable() { @Override public void run() { updateActions(); } }; if (SwingUtilities.isEventDispatchThread()) { runner.run(); } else { SwingUtilities.invokeLater(runner); } } /** Clears all current cursors. */ public void clearAllCursors() { for (int i = 0; i < CapturedData.MAX_CURSORS; i++) { this.dataContainer.setCursorPosition(i, null); } fireCursorChangedEvent(0, -1); // removed... updateActions(); } /** Clears the current device controller. */ public void clearDeviceController() { this.currentDevCtrl = null; } /** * Clears the current project, and start over as it were a new project, in which no captured data * is shown. */ public void createNewProject() { this.projectManager.createNewProject(); if (this.mainFrame != null) { this.mainFrame.repaint(); } updateActions(); } /** Exits the client application. */ public void exit() { if (this.host != null) { this.host.exit(); } } /** * Exports the current diagram to the given exporter. * * @param aExporter the exporter to export to, cannot be <code>null</code>. * @param aOutputStream the output stream to write the export to, cannot be <code>null</code>. * @throws IOException in case of I/O problems. */ public void exportTo(final Exporter aExporter, final OutputStream aOutputStream) throws IOException { if (this.mainFrame != null) { aExporter.export(this.dataContainer, this.mainFrame.getDiagramScrollPane(), aOutputStream); } } /** @see nl.lxtreme.ols.client.ActionProvider#getAction(java.lang.String) */ public Action getAction(final String aID) { return this.actionManager.getAction(aID); } /** @return the dataContainer */ public DataContainer getDataContainer() { return this.dataContainer; } /** * Returns the current device controller. * * @return the current device controller, can be <code>null</code>. */ public DeviceController getDeviceController() { return this.currentDevCtrl; } /** * Returns all current tools known to the OSGi framework. * * @return a collection of tools, never <code>null</code>. */ public final Collection<DeviceController> getDevices() { final List<DeviceController> tools = new ArrayList<DeviceController>(); synchronized (this.bundleContext) { try { final ServiceReference[] serviceRefs = this.bundleContext.getAllServiceReferences(DeviceController.class.getName(), null); for (ServiceReference serviceRef : serviceRefs) { tools.add((DeviceController) this.bundleContext.getService(serviceRef)); } } catch (InvalidSyntaxException exception) { throw new RuntimeException(exception); } } return tools; } /** * Returns the exporter with the given name. * * @param aName the name of the exporter to return, cannot be <code>null</code>. * @return the exporter with the given name, can be <code>null</code> if no such exporter is * found. * @throws IllegalArgumentException in case the given name was <code>null</code> or empty. */ public Exporter getExporter(final String aName) throws IllegalArgumentException { if ((aName == null) || aName.trim().isEmpty()) { throw new IllegalArgumentException("Name cannot be null or empty!"); } try { final ServiceReference[] serviceRefs = this.bundleContext.getAllServiceReferences(Exporter.class.getName(), null); final int count = (serviceRefs == null) ? 0 : serviceRefs.length; for (int i = 0; i < count; i++) { final Exporter exporter = (Exporter) this.bundleContext.getService(serviceRefs[i]); if (aName.equals(exporter.getName())) { return exporter; } } return null; } catch (InvalidSyntaxException exception) { throw new RuntimeException("getExporter failed!", exception); } } /** * Returns the names of all current available exporters. * * @return an array of exporter names, never <code>null</code>, but can be empty. */ public String[] getExporterNames() { try { final ServiceReference[] serviceRefs = this.bundleContext.getAllServiceReferences(Exporter.class.getName(), null); final int count = serviceRefs == null ? 0 : serviceRefs.length; final String[] result = new String[count]; for (int i = 0; i < count; i++) { final Exporter exporter = (Exporter) this.bundleContext.getService(serviceRefs[i]); result[i] = exporter.getName(); this.bundleContext.ungetService(serviceRefs[i]); } return result; } catch (InvalidSyntaxException exception) { throw new RuntimeException("getAllExporterNames failed!", exception); } } /** * Returns the current project's filename. * * @return a project filename, as file object, can be <code>null</code>. */ public File getProjectFilename() { return this.projectManager.getCurrentProject().getFilename(); } /** * Returns all current tools known to the OSGi framework. * * @return a collection of tools, never <code>null</code>. */ public final Collection<Tool> getTools() { final List<Tool> tools = new ArrayList<Tool>(); synchronized (this.bundleContext) { try { final ServiceReference[] serviceRefs = this.bundleContext.getAllServiceReferences(Tool.class.getName(), null); for (ServiceReference serviceRef : serviceRefs) { tools.add((Tool) this.bundleContext.getService(serviceRef)); } } catch (InvalidSyntaxException exception) { throw new RuntimeException(exception); } } return tools; } /** * Goes to the current cursor position of the cursor with the given index. * * @param aCursorIdx the index of the cursor to go to, >= 0 && < 10. */ public void gotoCursorPosition(final int aCursorIdx) { if ((this.mainFrame != null) && this.dataContainer.isCursorsEnabled()) { final Long cursorPosition = this.dataContainer.getCursorPosition(aCursorIdx); if (cursorPosition != null) { this.mainFrame.gotoPosition(cursorPosition.longValue()); } } } /** Goes to the current cursor position of the first available cursor. */ public void gotoFirstAvailableCursor() { if ((this.mainFrame != null) && this.dataContainer.isCursorsEnabled()) { for (int c = 0; c < CapturedData.MAX_CURSORS; c++) { if (this.dataContainer.isCursorPositionSet(c)) { final Long cursorPosition = this.dataContainer.getCursorPosition(c); if (cursorPosition != null) { this.mainFrame.gotoPosition(cursorPosition.longValue()); } break; } } } } /** Goes to the current cursor position of the last available cursor. */ public void gotoLastAvailableCursor() { if ((this.mainFrame != null) && this.dataContainer.isCursorsEnabled()) { for (int c = CapturedData.MAX_CURSORS - 1; c >= 0; c--) { if (this.dataContainer.isCursorPositionSet(c)) { final Long cursorPosition = this.dataContainer.getCursorPosition(c); if (cursorPosition != null) { this.mainFrame.gotoPosition(cursorPosition.longValue()); } break; } } } } /** Goes to the position of the trigger. */ public void gotoTriggerPosition() { if ((this.mainFrame != null) && this.dataContainer.hasTriggerData()) { final long position = this.dataContainer.getTriggerPosition(); this.mainFrame.gotoPosition(position); } } /** * Returns whether there is a device selected or not. * * @return <code>true</code> if there is a device selected, <code>false</code> if no device is * selected. */ public synchronized boolean isDeviceSelected() { return this.currentDevCtrl != null; } /** * Returns whether the current device is setup at least once. * * @return <code>true</code> if the current device is setup, <code>false</code> otherwise. * @see #isDeviceSelected() */ public synchronized boolean isDeviceSetup() { return (this.currentDevCtrl != null) && this.currentDevCtrl.isSetup(); } /** * Returns whether or not the current project is changed. * * @return <code>true</code> if the current project is changed, <code>false</code> if the current * project is not changed. */ public boolean isProjectChanged() { return this.projectManager.getCurrentProject().isChanged(); } /** * Loads an OLS data file from the given file. * * @param aFile the file to load as OLS data, cannot be <code>null</code>. * @throws IOException in case of I/O problems. */ public void openDataFile(final File aFile) throws IOException { final FileReader reader = new FileReader(aFile); try { final Project tempProject = this.projectManager.createTemporaryProject(); OlsDataHelper.read(tempProject, reader); setChannelLabels(tempProject.getChannelLabels()); setCapturedData(tempProject.getCapturedData()); setCursorData(tempProject.getCursorPositions(), tempProject.isCursorsEnabled()); } finally { reader.close(); zoomToFit(); updateActions(); } } /** * Opens the project denoted by the given file. * * @param aFile the project file to open, cannot be <code>null</code>. * @throws IOException in case of I/O problems. */ public void openProjectFile(final File aFile) throws IOException { FileInputStream fis = new FileInputStream(aFile); this.projectManager.loadProject(fis); final Project project = this.projectManager.getCurrentProject(); project.setFilename(aFile); zoomToFit(); } /** * Removes the cursor denoted by the given cursor index. * * @param aCursorIdx the index of the cursor to remove, >= 0 && < 10. */ public void removeCursor(final int aCursorIdx) { if (this.mainFrame != null) { this.dataContainer.setCursorPosition(aCursorIdx, null); fireCursorChangedEvent(aCursorIdx, -1); // removed... } updateActions(); } /** * Removes a cursor change listener. * * @param aListener the listener to remove, cannot be <code>null</code>. */ public void removeCursorChangeListener(final DiagramCursorChangeListener aListener) { this.evenListeners.remove(DiagramCursorChangeListener.class, aListener); } /** * Removes the given device from the list of devices. * * @param aDeviceController the device to remove, cannot be <code>null</code>. */ public void removeDevice(final DeviceController aDeviceController) { if (this.currentDevCtrl == aDeviceController) { this.currentDevCtrl = null; } if (this.mainFrame != null) { this.mainFrame.removeDeviceMenuItem(aDeviceController.getName()); } updateActions(); } /** * Removes the given exporter from the list of exporters. * * @param aExporter the exporter to remove, cannot be <code>null</code>. */ public void removeExporter(final Exporter aExporter) { if (this.mainFrame != null) { this.mainFrame.removeExportMenuItem(aExporter.getName()); } updateActions(); } /** * Removes the given tool from the list of tools. * * @param aTool the tool to remove, cannot be <code>null</code>. */ public void removeTool(final Tool aTool) { if (this.mainFrame != null) { this.mainFrame.removeToolMenuItem(aTool.getName()); } updateActions(); } /** * Repeats the capture with the current settings. * * @param aParent the parent window to use, can be <code>null</code>. */ public boolean repeatCaptureData(final Window aParent) { final DeviceController devCtrl = getDeviceController(); if (devCtrl == null) { return false; } try { setStatus( "Capture from {0} started at {1,date,medium} {1,time,medium} ...", devCtrl.getName(), new Date()); devCtrl.captureData(this); return true; } catch (IOException exception) { captureAborted("I/O problem: " + exception.getMessage()); exception.printStackTrace(); // Make sure to handle IO-interrupted exceptions properly! HostUtils.handleInterruptedException(exception); return false; } finally { updateActions(); } } /** * Runs the tool denoted by the given name. * * @param aToolName the name of the tool to run, cannot be <code>null</code>; * @param aParent the parent window to use, can be <code>null</code>. */ public void runTool(final String aToolName, final Window aParent) { if (LOG.isLoggable(Level.INFO)) { LOG.log(Level.INFO, "Running tool: \"{0}\" ...", aToolName); } final Tool tool = findToolByName(aToolName); if (tool == null) { JOptionPane.showMessageDialog( aParent, "No such tool found: " + aToolName, "Error ...", JOptionPane.ERROR_MESSAGE); } else { final ToolContext context = createToolContext(); tool.process(aParent, this.dataContainer, context, this); } updateActions(); } /** @see nl.lxtreme.ols.api.devices.CaptureCallback#samplesCaptured(java.util.List) */ @Override public void samplesCaptured(final List<Sample> aSamples) { if (this.mainFrame != null) { this.mainFrame.sampleCaptured(aSamples); } updateActions(); } /** * Saves an OLS data file to the given file. * * @param aFile the file to save the OLS data to, cannot be <code>null</code>. * @throws IOException in case of I/O problems. */ public void saveDataFile(final File aFile) throws IOException { final FileWriter writer = new FileWriter(aFile); try { final Project tempProject = this.projectManager.createTemporaryProject(); tempProject.setCapturedData(this.dataContainer); OlsDataHelper.write(tempProject, writer); } finally { writer.flush(); writer.close(); } } /** * Saves the current project to the given file. * * @param aFile the file to save the project information to, cannot be <code>null</code>. * @throws IOException in case of I/O problems. */ public void saveProjectFile(final String aName, final File aFile) throws IOException { FileOutputStream out = null; try { final Project project = this.projectManager.getCurrentProject(); project.setFilename(aFile); project.setName(aName); out = new FileOutputStream(aFile); this.projectManager.saveProject(out); } finally { HostUtils.closeResource(out); } } /** * Sets whether or not cursors are enabled. * * @param aState <code>true</code> if the cursors should be enabled, <code>false</code> otherwise. */ public void setCursorMode(final boolean aState) { this.dataContainer.setCursorEnabled(aState); // Reflect the change directly on the diagram... repaintMainFrame(); updateActions(); } /** * Sets the cursor position of the cursor with the given index. * * @param aCursorIdx the index of the cursor to set, >= 0 && < 10; * @param aLocation the mouse location on screen where the cursor should become, cannot be <code> * null</code>. */ public void setCursorPosition(final int aCursorIdx, final Point aLocation) { // Implicitly enable cursor mode, the user already had made its // intensions clear that he want to have this by opening up the // context menu anyway... setCursorMode(true); if (this.mainFrame != null) { // Convert the mouse-position to a sample index... final long sampleIdx = this.mainFrame.convertMousePositionToSampleIndex(aLocation); this.dataContainer.setCursorPosition(aCursorIdx, Long.valueOf(sampleIdx)); fireCursorChangedEvent(aCursorIdx, aLocation.x); } updateActions(); } /** * Sets the current device controller to the given value. * * @param aDeviceName the name of the device controller to set, cannot be <code>null</code>. */ public synchronized void setDeviceController(final String aDeviceName) { if (LOG.isLoggable(Level.INFO)) { final String name = (aDeviceName == null) ? "no device" : aDeviceName; LOG.log(Level.INFO, "Setting current device controller to: \"{0}\" ...", name); } final Collection<DeviceController> devices = getDevices(); for (DeviceController device : devices) { if (aDeviceName.equals(device.getName())) { this.currentDevCtrl = device; } } updateActions(); } /** @param aMainFrame the mainFrame to set */ public void setMainFrame(final MainFrame aMainFrame) { if (this.mainFrame != null) { this.projectManager.removePropertyChangeListener(this.mainFrame); } if (aMainFrame != null) { this.projectManager.addPropertyChangeListener(aMainFrame); } this.mainFrame = aMainFrame; } /** * Sets a status message. * * @param aMessage the message to set; * @param aMessageArgs the (optional) message arguments. */ public final void setStatus(final String aMessage, final Object... aMessageArgs) { if (this.mainFrame != null) { this.mainFrame.setStatus(aMessage, aMessageArgs); } } /** Shows the "about OLS" dialog on screen. the parent window to use, can be <code>null</code>. */ public void showAboutBox() { MainFrame.showAboutBox(this.host.getVersion()); } /** * Shows a dialog with all running OSGi bundles. * * @param aOwner the owning window to use, can be <code>null</code>. */ public void showBundlesDialog(final Window aOwner) { BundlesDialog dialog = new BundlesDialog(aOwner, this.bundleContext); if (dialog.showDialog()) { dialog.dispose(); dialog = null; } } /** * Shows the label-editor dialog on screen. * * <p>Display the diagram labels dialog. Will block until the dialog is closed again. * * @param aParent the parent window to use, can be <code>null</code>. */ public void showLabelsDialog(final Window aParent) { if (this.mainFrame != null) { DiagramLabelsDialog dialog = new DiagramLabelsDialog(aParent, this.dataContainer.getChannelLabels()); if (dialog.showDialog()) { final String[] channelLabels = dialog.getChannelLabels(); setChannelLabels(channelLabels); } dialog.dispose(); dialog = null; } } /** * Shows the settings-editor dialog on screen. * * <p>Display the diagram settings dialog. Will block until the dialog is closed again. * * @param aParent the parent window to use, can be <code>null</code>. */ public void showModeSettingsDialog(final Window aParent) { if (this.mainFrame != null) { ModeSettingsDialog dialog = new ModeSettingsDialog(aParent, getDiagramSettings()); if (dialog.showDialog()) { updateDiagramSettings(dialog.getDiagramSettings()); } dialog.dispose(); dialog = null; } } /** @param aOwner */ public void showPreferencesDialog(final Window aParent) { GeneralSettingsDialog dialog = new GeneralSettingsDialog(aParent, getDiagramSettings()); if (dialog.showDialog()) { updateDiagramSettings(dialog.getDiagramSettings()); } dialog.dispose(); dialog = null; } /** @see nl.lxtreme.ols.api.ProgressCallback#updateProgress(int) */ @Override public void updateProgress(final int aPercentage) { if (this.mainFrame != null) { this.mainFrame.setProgress(aPercentage); } } /** Zooms in to the maximum zoom level. */ public void zoomDefault() { if (this.mainFrame != null) { this.mainFrame.zoomDefault(); } updateActions(); } /** Zooms in with a factor of 2.0. */ public void zoomIn() { if (this.mainFrame != null) { this.mainFrame.zoomIn(); } updateActions(); } /** Zooms out with a factor of 2.0. */ public void zoomOut() { if (this.mainFrame != null) { this.mainFrame.zoomOut(); } updateActions(); } /** Zooms to fit the diagram to the current window dimensions. */ public void zoomToFit() { if (this.mainFrame != null) { this.mainFrame.zoomToFit(); } updateActions(); } /** * Returns the current main frame. * * @return the main frame, can be <code>null</code>. */ final MainFrame getMainFrame() { return this.mainFrame; } /** * Creates the tool context denoting the range of samples that should be analysed by a tool. * * @return a tool context, never <code>null</code>. */ private ToolContext createToolContext() { int startOfDecode = -1; int endOfDecode = -1; final int dataLength = this.dataContainer.getValues().length; if (this.dataContainer.isCursorsEnabled()) { if (this.dataContainer.isCursorPositionSet(0)) { final Long cursor1 = this.dataContainer.getCursorPosition(0); startOfDecode = this.dataContainer.getSampleIndex(cursor1.longValue()) - 1; } if (this.dataContainer.isCursorPositionSet(1)) { final Long cursor2 = this.dataContainer.getCursorPosition(1); endOfDecode = this.dataContainer.getSampleIndex(cursor2.longValue()) + 1; } } else { startOfDecode = 0; endOfDecode = dataLength; } startOfDecode = Math.max(0, startOfDecode); if ((endOfDecode < 0) || (endOfDecode >= dataLength)) { endOfDecode = dataLength - 1; } return new DefaultToolContext(startOfDecode, endOfDecode); } /** @param aActionManager */ private void fillActionManager(final ActionManager aActionManager) { aActionManager.add(new NewProjectAction(this)); aActionManager.add(new OpenProjectAction(this)); aActionManager.add(new SaveProjectAction(this)).setEnabled(false); aActionManager.add(new SaveProjectAsAction(this)).setEnabled(false); aActionManager.add(new OpenDataFileAction(this)); aActionManager.add(new SaveDataFileAction(this)).setEnabled(false); aActionManager.add(new ExitAction(this)); aActionManager.add(new CaptureAction(this)); aActionManager.add(new CancelCaptureAction(this)).setEnabled(false); aActionManager.add(new RepeatCaptureAction(this)).setEnabled(false); aActionManager.add(new ZoomInAction(this)).setEnabled(false); aActionManager.add(new ZoomOutAction(this)).setEnabled(false); aActionManager.add(new ZoomDefaultAction(this)).setEnabled(false); aActionManager.add(new ZoomFitAction(this)).setEnabled(false); aActionManager.add(new GotoTriggerAction(this)).setEnabled(false); for (int c = 0; c < CapturedData.MAX_CURSORS; c++) { aActionManager.add(new GotoNthCursorAction(this, c)).setEnabled(false); } aActionManager.add(new GotoFirstCursorAction(this)).setEnabled(false); aActionManager.add(new GotoLastCursorAction(this)).setEnabled(false); aActionManager.add(new ClearCursors(this)).setEnabled(false); aActionManager.add(new SetCursorModeAction(this)); for (int c = 0; c < CapturedData.MAX_CURSORS; c++) { aActionManager.add(new SetCursorAction(this, c)); } aActionManager.add(new ShowGeneralSettingsAction(this)); aActionManager.add(new ShowModeSettingsAction(this)); aActionManager.add(new ShowDiagramLabelsAction(this)); aActionManager.add(new HelpAboutAction(this)); aActionManager.add(new ShowBundlesAction(this)); } /** * Searches for the tool with the given name. * * @param aToolName the name of the tool to search for, cannot be <code>null</code>. * @return the tool with the given name, can be <code>null</code> if no such tool can be found. */ private Tool findToolByName(final String aToolName) { Tool tool = null; final Collection<Tool> tools = getTools(); for (Tool _tool : tools) { if (aToolName.equals(_tool.getName())) { tool = _tool; break; } } return tool; } /** * @param aCursorIdx * @param aMouseXpos */ private void fireCursorChangedEvent(final int aCursorIdx, final int aMouseXpos) { final DiagramCursorChangeListener[] listeners = this.evenListeners.getListeners(DiagramCursorChangeListener.class); for (final DiagramCursorChangeListener listener : listeners) { if (aMouseXpos >= 0) { listener.cursorChanged(aCursorIdx, aMouseXpos); } else { listener.cursorRemoved(aCursorIdx); } } } /** * Returns the current diagram settings. * * @return the current diagram settings, can be <code>null</code> if there is no main frame to * take the settings from. */ private DiagramSettings getDiagramSettings() { return this.mainFrame != null ? this.mainFrame.getDiagramSettings() : null; } /** Dispatches a request to repaint the entire main frame. */ private void repaintMainFrame() { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { ClientController.this.mainFrame.repaint(); } }); } /** * Sets the captured data and zooms the view to show all the data. * * @param aCapturedData the new captured data to set, cannot be <code>null</code>. */ private void setCapturedData(final CapturedData aCapturedData) { this.dataContainer.setCapturedData(aCapturedData); if (this.mainFrame != null) { this.mainFrame.zoomToFit(); } } /** * Set the channel labels. * * @param aChannelLabels the channel labels to set, cannot be <code>null</code>. */ private void setChannelLabels(final String[] aChannelLabels) { if (aChannelLabels != null) { this.dataContainer.setChannelLabels(aChannelLabels); this.mainFrame.setChannelLabels(aChannelLabels); } } /** * @param aCursorData the cursor positions to set, cannot be <code>null</code>; * @param aCursorsEnabled <code>true</code> if cursors should be enabled, <code>false</code> if * they should be disabled. */ private void setCursorData(final Long[] aCursorData, final boolean aCursorsEnabled) { this.dataContainer.setCursorEnabled(aCursorsEnabled); for (int i = 0; i < CapturedData.MAX_CURSORS; i++) { this.dataContainer.setCursorPosition(i, aCursorData[i]); } } /** Synchronizes the state of the actions to the current state of this host. */ private void updateActions() { final DeviceController currentDeviceController = getDeviceController(); final boolean deviceControllerSet = currentDeviceController != null; final boolean deviceCapturing = deviceControllerSet && currentDeviceController.isCapturing(); final boolean deviceSetup = deviceControllerSet && !deviceCapturing && currentDeviceController.isSetup(); getAction(CaptureAction.ID).setEnabled(deviceControllerSet); getAction(CancelCaptureAction.ID).setEnabled(deviceCapturing); getAction(RepeatCaptureAction.ID).setEnabled(deviceSetup); final boolean projectChanged = this.projectManager.getCurrentProject().isChanged(); final boolean projectSavedBefore = this.projectManager.getCurrentProject().getFilename() != null; final boolean dataAvailable = this.dataContainer.hasCapturedData(); getAction(SaveProjectAction.ID).setEnabled(projectChanged); getAction(SaveProjectAsAction.ID).setEnabled(projectSavedBefore && projectChanged); getAction(SaveDataFileAction.ID).setEnabled(dataAvailable); getAction(ZoomInAction.ID).setEnabled(dataAvailable); getAction(ZoomOutAction.ID).setEnabled(dataAvailable); getAction(ZoomDefaultAction.ID).setEnabled(dataAvailable); getAction(ZoomFitAction.ID).setEnabled(dataAvailable); final boolean triggerEnable = dataAvailable && this.dataContainer.hasTriggerData(); getAction(GotoTriggerAction.ID).setEnabled(triggerEnable); // Update the cursor actions accordingly... final boolean enableCursors = dataAvailable && this.dataContainer.isCursorsEnabled(); for (int c = 0; c < CapturedData.MAX_CURSORS; c++) { final boolean enabled = enableCursors && this.dataContainer.isCursorPositionSet(c); getAction(GotoNthCursorAction.getID(c)).setEnabled(enabled); } getAction(GotoFirstCursorAction.ID).setEnabled(enableCursors); getAction(GotoLastCursorAction.ID).setEnabled(enableCursors); getAction(SetCursorModeAction.ID).setEnabled(dataAvailable); getAction(SetCursorModeAction.ID) .putValue(Action.SELECTED_KEY, Boolean.valueOf(this.dataContainer.isCursorsEnabled())); boolean anyCursorSet = false; for (int c = 0; c < CapturedData.MAX_CURSORS; c++) { final boolean cursorPositionSet = this.dataContainer.isCursorPositionSet(c); anyCursorSet |= cursorPositionSet; final Action action = getAction(SetCursorAction.getCursorId(c)); action.setEnabled(dataAvailable); action.putValue(Action.SELECTED_KEY, Boolean.valueOf(cursorPositionSet)); } getAction(ClearCursors.ID).setEnabled(enableCursors && anyCursorSet); } /** * Should be called after the diagram settings are changed. This method will cause the settings to * be set on the main frame and writes them to the preference store. * * @param aSettings the (new/changed) diagram settings to set, cannot be <code>null</code>. */ private void updateDiagramSettings(final DiagramSettings aSettings) { if (this.mainFrame != null) { this.mainFrame.setDiagramSettings(aSettings); repaintMainFrame(); } } }
/** * @author Emil Ivov * @author Lyubomir Marinov */ public class ConfigurationActivator implements BundleActivator { /** The <tt>Logger</tt> used by the <tt>ConfigurationActivator</tt> class for logging output. */ private static final Logger logger = Logger.getLogger(ConfigurationActivator.class); /** The currently registered {@link ConfigurationService} instance. */ private ConfigurationService cs; /** * Starts the configuration service * * @param bundleContext the <tt>BundleContext</tt> as provided by the OSGi framework. * @throws Exception if anything goes wrong */ public void start(BundleContext bundleContext) throws Exception { FileAccessService fas = ServiceUtils.getService(bundleContext, FileAccessService.class); if (fas != null) { File usePropFileConfig; try { usePropFileConfig = fas.getPrivatePersistentFile(".usepropfileconfig", FileCategory.PROFILE); } catch (Exception ise) { // There is somewhat of a chicken-and-egg dependency between // FileConfigurationServiceImpl and ConfigurationServiceImpl: // FileConfigurationServiceImpl throws IllegalStateException if // certain System properties are not set, // ConfigurationServiceImpl will make sure that these properties // are set but it will do that later. // A SecurityException is thrown when the destination // is not writable or we do not have access to that folder usePropFileConfig = null; } if (usePropFileConfig != null && usePropFileConfig.exists()) { logger.info("Using properties file configuration store."); this.cs = LibJitsi.getConfigurationService(); } } if (this.cs == null) { this.cs = new JdbcConfigService(fas); } bundleContext.registerService(ConfigurationService.class.getName(), this.cs, null); fixPermissions(this.cs); } /** * Causes the configuration service to store the properties object and unregisters the * configuration service. * * @param bundleContext <tt>BundleContext</tt> * @throws Exception if anything goes wrong while storing the properties managed by the * <tt>ConfigurationService</tt> implementation provided by this bundle and while * unregistering the service in question */ public void stop(BundleContext bundleContext) throws Exception { this.cs.storeConfiguration(); this.cs = null; } /** * Makes home folder and the configuration file readable and writable only to the owner. * * @param cs the <tt>ConfigurationService</tt> instance to check for home folder and configuration * file. */ private static void fixPermissions(ConfigurationService cs) { if (!OSUtils.IS_LINUX && !OSUtils.IS_MAC) return; try { // let's check config file and config folder File homeFolder = new File(cs.getScHomeDirLocation(), cs.getScHomeDirName()); Set<PosixFilePermission> perms = new HashSet<PosixFilePermission>() { { add(PosixFilePermission.OWNER_READ); add(PosixFilePermission.OWNER_WRITE); add(PosixFilePermission.OWNER_EXECUTE); } }; Files.setPosixFilePermissions(Paths.get(homeFolder.getAbsolutePath()), perms); String fileName = cs.getConfigurationFilename(); if (fileName != null) { File cf = new File(homeFolder, fileName); if (cf.exists()) { perms = new HashSet<PosixFilePermission>() { { add(PosixFilePermission.OWNER_READ); add(PosixFilePermission.OWNER_WRITE); } }; Files.setPosixFilePermissions(Paths.get(cf.getAbsolutePath()), perms); } } } catch (Throwable t) { logger.error("Error creating c lib instance for fixing file permissions", t); if (t instanceof InterruptedException) Thread.currentThread().interrupt(); else if (t instanceof ThreadDeath) throw (ThreadDeath) t; } } }
/** * The ProtocolProviderFactory is what actually creates instances of a ProtocolProviderService * implementation. A provider factory would register, persistently store, and remove when necessary, * ProtocolProviders. The way things are in the SIP Communicator, a user account is represented (in * a 1:1 relationship) by an AccountID and a ProtocolProvider. In other words - one would have as * many protocol providers installed in a given moment as they would user account registered through * the various services. * * @author Emil Ivov * @author Lubomir Marinov */ public abstract class ProtocolProviderFactory { /** * The <tt>Logger</tt> used by the <tt>ProtocolProviderFactory</tt> class and its instances for * logging output. */ private static final Logger logger = Logger.getLogger(ProtocolProviderFactory.class); /** Then name of a property which represents a password. */ public static final String PASSWORD = "******"; /** * The name of a property representing the name of the protocol for an ProtocolProviderFactory. */ public static final String PROTOCOL = "PROTOCOL_NAME"; /** The name of a property representing the path to protocol icons. */ public static final String PROTOCOL_ICON_PATH = "PROTOCOL_ICON_PATH"; /** * The name of a property representing the path to the account icon to be used in the user * interface, when the protocol provider service is not available. */ public static final String ACCOUNT_ICON_PATH = "ACCOUNT_ICON_PATH"; /** * The name of a property which represents the AccountID of a ProtocolProvider and that, together * with a password is used to login on the protocol network.. */ public static final String USER_ID = "USER_ID"; /** The name that should be displayed to others when we are calling or writing them. */ public static final String DISPLAY_NAME = "DISPLAY_NAME"; /** The name that should be displayed to the user on call via and chat via lists. */ public static final String ACCOUNT_DISPLAY_NAME = "ACCOUNT_DISPLAY_NAME"; /** The name of the property under which we store protocol AccountID-s. */ public static final String ACCOUNT_UID = "ACCOUNT_UID"; /** * The name of the property under which we store protocol the address of a protocol centric entity * (any protocol server). */ public static final String SERVER_ADDRESS = "SERVER_ADDRESS"; /** * The name of the property under which we store the number of the port where the server stored * against the SERVER_ADDRESS property is expecting connections to be made via this protocol. */ public static final String SERVER_PORT = "SERVER_PORT"; /** * The name of the property under which we store the name of the transport protocol that needs to * be used to access the server. */ public static final String SERVER_TRANSPORT = "SERVER_TRANSPORT"; /** The name of the property under which we store protocol the address of a protocol proxy. */ public static final String PROXY_ADDRESS = "PROXY_ADDRESS"; /** * The name of the property under which we store the number of the port where the proxy stored * against the PROXY_ADDRESS property is expecting connections to be made via this protocol. */ public static final String PROXY_PORT = "PROXY_PORT"; /** * The name of the property which defines whether proxy is auto configured by the protocol by * using known methods such as specific DNS queries. */ public static final String PROXY_AUTO_CONFIG = "PROXY_AUTO_CONFIG"; /** The property indicating the preferred UDP and TCP port to bind to for clear communications. */ public static final String PREFERRED_CLEAR_PORT_PROPERTY_NAME = "net.java.sip.communicator.SIP_PREFERRED_CLEAR_PORT"; /** The property indicating the preferred TLS (TCP) port to bind to for secure communications. */ public static final String PREFERRED_SECURE_PORT_PROPERTY_NAME = "net.java.sip.communicator.SIP_PREFERRED_SECURE_PORT"; /** * The name of the property under which we store the the type of the proxy stored against the * PROXY_ADDRESS property. Exact type values depend on protocols and among them are socks4, * socks5, http and possibly others. */ public static final String PROXY_TYPE = "PROXY_TYPE"; /** * The name of the property under which we store the the username for the proxy stored against the * PROXY_ADDRESS property. */ public static final String PROXY_USERNAME = "******"; /** * The name of the property under which we store the the authorization name for the proxy stored * against the PROXY_ADDRESS property. */ public static final String AUTHORIZATION_NAME = "AUTHORIZATION_NAME"; /** * The name of the property under which we store the password for the proxy stored against the * PROXY_ADDRESS property. */ public static final String PROXY_PASSWORD = "******"; /** * The name of the property under which we store the name of the transport protocol that needs to * be used to access the proxy. */ public static final String PROXY_TRANSPORT = "PROXY_TRANSPORT"; /** * The name of the property that indicates whether loose routing should be forced for all traffic * in an account, rather than routing through an outbound proxy which is the default for Jitsi. */ public static final String FORCE_PROXY_BYPASS = "******"; /** * The name of the property under which we store the user preference for a transport protocol to * use (i.e. tcp or udp). */ public static final String PREFERRED_TRANSPORT = "PREFERRED_TRANSPORT"; /** * The name of the property under which we store whether we generate resource values or we just * use the stored one. */ public static final String AUTO_GENERATE_RESOURCE = "AUTO_GENERATE_RESOURCE"; /** * The name of the property under which we store resources such as the jabber resource property. */ public static final String RESOURCE = "RESOURCE"; /** The name of the property under which we store resource priority. */ public static final String RESOURCE_PRIORITY = "RESOURCE_PRIORITY"; /** The name of the property which defines that the call is encrypted by default */ public static final String DEFAULT_ENCRYPTION = "DEFAULT_ENCRYPTION"; /** The name of the property that indicates the encryption protocols for this account. */ public static final String ENCRYPTION_PROTOCOL = "ENCRYPTION_PROTOCOL"; /** * The name of the property that indicates the status (enabed or disabled) encryption protocols * for this account. */ public static final String ENCRYPTION_PROTOCOL_STATUS = "ENCRYPTION_PROTOCOL_STATUS"; /** The name of the property which defines if to include the ZRTP attribute to SIP/SDP */ public static final String DEFAULT_SIPZRTP_ATTRIBUTE = "DEFAULT_SIPZRTP_ATTRIBUTE"; /** * The name of the property which defines the ID of the client TLS certificate configuration * entry. */ public static final String CLIENT_TLS_CERTIFICATE = "CLIENT_TLS_CERTIFICATE"; /** * The name of the property under which we store the boolean value indicating if the user name * should be automatically changed if the specified name already exists. This property is meant to * be used by IRC implementations. */ public static final String AUTO_CHANGE_USER_NAME = "AUTO_CHANGE_USER_NAME"; /** * The name of the property under which we store the boolean value indicating if a password is * required. Initially this property is meant to be used by IRC implementations. */ public static final String NO_PASSWORD_REQUIRED = "NO_PASSWORD_REQUIRED"; /** The name of the property under which we store if the presence is enabled. */ public static final String IS_PRESENCE_ENABLED = "IS_PRESENCE_ENABLED"; /** The name of the property under which we store if the p2p mode for SIMPLE should be forced. */ public static final String FORCE_P2P_MODE = "FORCE_P2P_MODE"; /** * The name of the property under which we store the offline contact polling period for SIMPLE. */ public static final String POLLING_PERIOD = "POLLING_PERIOD"; /** * The name of the property under which we store the chosen default subscription expiration value * for SIMPLE. */ public static final String SUBSCRIPTION_EXPIRATION = "SUBSCRIPTION_EXPIRATION"; /** Indicates if the server address has been validated. */ public static final String SERVER_ADDRESS_VALIDATED = "SERVER_ADDRESS_VALIDATED"; /** Indicates if the server settings are over */ public static final String IS_SERVER_OVERRIDDEN = "IS_SERVER_OVERRIDDEN"; /** Indicates if the proxy address has been validated. */ public static final String PROXY_ADDRESS_VALIDATED = "PROXY_ADDRESS_VALIDATED"; /** Indicates the search strategy chosen for the DICT protocole. */ public static final String STRATEGY = "STRATEGY"; /** Indicates a protocol that would not be shown in the user interface as an account. */ public static final String IS_PROTOCOL_HIDDEN = "IS_PROTOCOL_HIDDEN"; /** Indicates if the given account is the preferred account. */ public static final String IS_PREFERRED_PROTOCOL = "IS_PREFERRED_PROTOCOL"; /** * The name of the property that would indicate if a given account is currently enabled or * disabled. */ public static final String IS_ACCOUNT_DISABLED = "IS_ACCOUNT_DISABLED"; /** Indicates if ICE should be used. */ public static final String IS_USE_ICE = "ICE_ENABLED"; /** Indicates if Google ICE should be used. */ public static final String IS_USE_GOOGLE_ICE = "GTALK_ICE_ENABLED"; /** Indicates if STUN server should be automatically discovered. */ public static final String AUTO_DISCOVER_STUN = "AUTO_DISCOVER_STUN"; /** Indicates if default STUN server would be used if no other STUN/TURN server are available. */ public static final String USE_DEFAULT_STUN_SERVER = "USE_DEFAULT_STUN_SERVER"; /** * The name of the boolean account property which indicates whether Jitsi VideoBridge is to be * used, if available and supported, for conference calls. */ public static final String USE_JITSI_VIDEO_BRIDGE = "USE_JITSI_VIDEO_BRIDGE"; /** * The property name prefix for all stun server properties. We generally use this prefix in * conjunction with an index which is how we store multiple servers. */ public static final String STUN_PREFIX = "STUN"; /** The base property name for address of additional STUN servers specified. */ public static final String STUN_ADDRESS = "ADDRESS"; /** The base property name for port of additional STUN servers specified. */ public static final String STUN_PORT = "PORT"; /** The base property name for username of additional STUN servers specified. */ public static final String STUN_USERNAME = "******"; /** The base property name for password of additional STUN servers specified. */ public static final String STUN_PASSWORD = "******"; /** * The base property name for the turn supported property of additional STUN servers specified. */ public static final String STUN_IS_TURN_SUPPORTED = "IS_TURN_SUPPORTED"; /** Indicates if JingleNodes should be used with ICE. */ public static final String IS_USE_JINGLE_NODES = "JINGLE_NODES_ENABLED"; /** Indicates if JingleNodes should be used with ICE. */ public static final String AUTO_DISCOVER_JINGLE_NODES = "AUTO_DISCOVER_JINGLE_NODES"; /** Indicates if JingleNodes should use buddies to search for nodes. */ public static final String JINGLE_NODES_SEARCH_BUDDIES = "JINGLE_NODES_SEARCH_BUDDIES"; /** Indicates if UPnP should be used with ICE. */ public static final String IS_USE_UPNP = "UPNP_ENABLED"; /** Indicates if we allow non-TLS connection. */ public static final String IS_ALLOW_NON_SECURE = "ALLOW_NON_SECURE"; /** Enable notifications for new voicemail messages. */ public static final String VOICEMAIL_ENABLED = "VOICEMAIL_ENABLED"; /** * Address used to reach voicemail box, by services able to subscribe for voicemail new messages * notifications. */ public static final String VOICEMAIL_URI = "VOICEMAIL_URI"; /** Address used to call to hear your messages stored on the server for your voicemail. */ public static final String VOICEMAIL_CHECK_URI = "VOICEMAIL_CHECK_URI"; /** Indicates if calling is disabled for a certain account. */ public static final String IS_CALLING_DISABLED_FOR_ACCOUNT = "CALLING_DISABLED"; /** Indicates if desktop streaming/sharing is disabled for a certain account. */ public static final String IS_DESKTOP_STREAMING_DISABLED = "DESKTOP_STREAMING_DISABLED"; /** The sms default server address. */ public static final String SMS_SERVER_ADDRESS = "SMS_SERVER_ADDRESS"; /** Keep-alive method used by the protocol. */ public static final String KEEP_ALIVE_METHOD = "KEEP_ALIVE_METHOD"; /** The interval for keep-alives if any. */ public static final String KEEP_ALIVE_INTERVAL = "KEEP_ALIVE_INTERVAL"; /** The minimal DTMF tone duration. */ public static final String DTMF_MINIMAL_TONE_DURATION = "DTMF_MINIMAL_TONE_DURATION"; /** Paranoia mode when turned on requires all calls to be secure and indicated as such. */ public static final String MODE_PARANOIA = "MODE_PARANOIA"; /** The name of the "override encodings" property */ public static final String OVERRIDE_ENCODINGS = "OVERRIDE_ENCODINGS"; /** The prefix used to store account encoding properties */ public static final String ENCODING_PROP_PREFIX = "Encodings"; /** * The <code>BundleContext</code> containing (or to contain) the service registration of this * factory. */ private final BundleContext bundleContext; /** * The name of the protocol this factory registers its <code>ProtocolProviderService</code>s with * and to be placed in the properties of the accounts created by this factory. */ private final String protocolName; /** * The table that we store our accounts in. * * <p>TODO Synchronize the access to the field which may in turn be better achieved by also hiding * it from protected into private access. */ protected final Hashtable<AccountID, ServiceRegistration> registeredAccounts = new Hashtable<AccountID, ServiceRegistration>(); /** * The name of the property that indicates the AVP type. * * <ul> * <li>{@link #SAVP_OFF} * <li>{@link #SAVP_MANDATORY} * <li>{@link #SAVP_OPTIONAL} * </ul> */ public static final String SAVP_OPTION = "SAVP_OPTION"; /** Always use RTP/AVP */ public static final int SAVP_OFF = 0; /** Always use RTP/SAVP */ public static final int SAVP_MANDATORY = 1; /** Sends two media description, with RTP/SAVP being first. */ public static final int SAVP_OPTIONAL = 2; /** * The name of the property that defines the enabled SDES cipher suites. Enabled suites are listed * as CSV by their RFC name. */ public static final String SDES_CIPHER_SUITES = "SDES_CIPHER_SUITES"; /** * Creates a new <tt>ProtocolProviderFactory</tt>. * * @param bundleContext the bundle context reference of the service * @param protocolName the name of the protocol */ protected ProtocolProviderFactory(BundleContext bundleContext, String protocolName) { this.bundleContext = bundleContext; this.protocolName = protocolName; } /** * Gets the <code>BundleContext</code> containing (or to contain) the service registration of this * factory. * * @return the <code>BundleContext</code> containing (or to contain) the service registration of * this factory */ public BundleContext getBundleContext() { return bundleContext; } /** * Initializes and creates an account corresponding to the specified accountProperties and * registers the resulting ProtocolProvider in the <tt>context</tt> BundleContext parameter. Note * that account registration is persistent and accounts that are registered during a particular * sip-communicator session would be automatically reloaded during all following sessions until * they are removed through the removeAccount method. * * @param userID the user identifier uniquely representing the newly created account within the * protocol namespace. * @param accountProperties a set of protocol (or implementation) specific properties defining the * new account. * @return the AccountID of the newly created account. * @throws java.lang.IllegalArgumentException if userID does not correspond to an identifier in * the context of the underlying protocol or if accountProperties does not contain a complete * set of account installation properties. * @throws java.lang.IllegalStateException if the account has already been installed. * @throws java.lang.NullPointerException if any of the arguments is null. */ public abstract AccountID installAccount(String userID, Map<String, String> accountProperties) throws IllegalArgumentException, IllegalStateException, NullPointerException; /** * Modifies the account corresponding to the specified accountID. This method is meant to be used * to change properties of already existing accounts. Note that if the given accountID doesn't * correspond to any registered account this method would do nothing. * * @param protocolProvider the protocol provider service corresponding to the modified account. * @param accountProperties a set of protocol (or implementation) specific properties defining the * new account. * @throws java.lang.NullPointerException if any of the arguments is null. */ public abstract void modifyAccount( ProtocolProviderService protocolProvider, Map<String, String> accountProperties) throws NullPointerException; /** * Returns a copy of the list containing the <tt>AccountID</tt>s of all accounts currently * registered in this protocol provider. * * @return a copy of the list containing the <tt>AccountID</tt>s of all accounts currently * registered in this protocol provider. */ public ArrayList<AccountID> getRegisteredAccounts() { synchronized (registeredAccounts) { return new ArrayList<AccountID>(registeredAccounts.keySet()); } } /** * Returns the ServiceReference for the protocol provider corresponding to the specified accountID * or null if the accountID is unknown. * * @param accountID the accountID of the protocol provider we'd like to get * @return a ServiceReference object to the protocol provider with the specified account id and * null if the account id is unknown to the provider factory. */ public ServiceReference getProviderForAccount(AccountID accountID) { ServiceRegistration registration; synchronized (registeredAccounts) { registration = registeredAccounts.get(accountID); } return (registration == null) ? null : registration.getReference(); } /** * Removes the specified account from the list of accounts that this provider factory is handling. * If the specified accountID is unknown to the ProtocolProviderFactory, the call has no effect * and false is returned. This method is persistent in nature and once called the account * corresponding to the specified ID will not be loaded during future runs of the project. * * @param accountID the ID of the account to remove. * @return true if an account with the specified ID existed and was removed and false otherwise. */ public boolean uninstallAccount(AccountID accountID) { // Unregister the protocol provider. ServiceReference serRef = getProviderForAccount(accountID); boolean wasAccountExisting = false; // If the protocol provider service is registered, first unregister the // service. if (serRef != null) { BundleContext bundleContext = getBundleContext(); ProtocolProviderService protocolProvider = (ProtocolProviderService) bundleContext.getService(serRef); try { protocolProvider.unregister(); } catch (OperationFailedException ex) { logger.error( "Failed to unregister protocol provider for account: " + accountID + " caused by: " + ex); } } ServiceRegistration registration; synchronized (registeredAccounts) { registration = registeredAccounts.remove(accountID); } // first remove the stored account so when PP is unregistered we can // distinguish between deleted or just disabled account wasAccountExisting = removeStoredAccount(accountID); if (registration != null) { // Kill the service. registration.unregister(); } return wasAccountExisting; } /** * The method stores the specified account in the configuration service under the package name of * the source factory. The restore and remove account methods are to be used to obtain access to * and control the stored accounts. * * <p>In order to store all account properties, the method would create an entry in the * configuration service corresponding (beginning with) the <tt>sourceFactory</tt>'s package name * and add to it a unique identifier (e.g. the current miliseconds.) * * @param accountID the AccountID corresponding to the account that we would like to store. */ protected void storeAccount(AccountID accountID) { this.storeAccount(accountID, true); } /** * The method stores the specified account in the configuration service under the package name of * the source factory. The restore and remove account methods are to be used to obtain access to * and control the stored accounts. * * <p>In order to store all account properties, the method would create an entry in the * configuration service corresponding (beginning with) the <tt>sourceFactory</tt>'s package name * and add to it a unique identifier (e.g. the current miliseconds.) * * @param accountID the AccountID corresponding to the account that we would like to store. * @param isModification if <tt>false</tt> there must be no such already loaded account, it * <tt>true</tt> ist modification of an existing account. Usually we use this method with * <tt>false</tt> in method installAccount and with <tt>true</tt> or the overridden method in * method modifyAccount. */ protected void storeAccount(AccountID accountID, boolean isModification) { if (!isModification && getAccountManager().getStoredAccounts().contains(accountID)) { throw new IllegalStateException( "An account for id " + accountID.getUserID() + " was already loaded!"); } try { getAccountManager().storeAccount(this, accountID); } catch (OperationFailedException ofex) { throw new UndeclaredThrowableException(ofex); } } /** * Saves the password for the specified account after scrambling it a bit so that it is not * visible from first sight. (The method remains highly insecure). * * @param accountID the AccountID for the account whose password we're storing * @param password the password itself * @throws IllegalArgumentException if no account corresponding to <code>accountID</code> has been * previously stored */ public void storePassword(AccountID accountID, String password) throws IllegalArgumentException { try { storePassword(getBundleContext(), accountID, password); } catch (OperationFailedException ofex) { throw new UndeclaredThrowableException(ofex); } } /** * Saves the password for the specified account after scrambling it a bit so that it is not * visible from first sight (Method remains highly insecure). * * <p>TODO Delegate the implementation to {@link AccountManager} because it knows the format in * which the password (among the other account properties) is to be saved. * * @param bundleContext a currently valid bundle context. * @param accountID the <tt>AccountID</tt> of the account whose password is to be stored * @param password the password to be stored * @throws IllegalArgumentException if no account corresponding to <tt>accountID</tt> has been * previously stored. * @throws OperationFailedException if anything goes wrong while storing the specified * <tt>password</tt> */ protected void storePassword(BundleContext bundleContext, AccountID accountID, String password) throws IllegalArgumentException, OperationFailedException { String accountPrefix = findAccountPrefix(bundleContext, accountID, getFactoryImplPackageName()); if (accountPrefix == null) { throw new IllegalArgumentException( "No previous records found for account ID: " + accountID.getAccountUniqueID() + " in package" + getFactoryImplPackageName()); } CredentialsStorageService credentialsStorage = ServiceUtils.getService(bundleContext, CredentialsStorageService.class); if (!credentialsStorage.storePassword(accountPrefix, password)) { throw new OperationFailedException( "CredentialsStorageService failed to storePassword", OperationFailedException.GENERAL_ERROR); } } /** * Returns the password last saved for the specified account. * * @param accountID the AccountID for the account whose password we're looking for * @return a String containing the password for the specified accountID */ public String loadPassword(AccountID accountID) { return loadPassword(getBundleContext(), accountID); } /** * Returns the password last saved for the specified account. * * <p>TODO Delegate the implementation to {@link AccountManager} because it knows the format in * which the password (among the other account properties) was saved. * * @param bundleContext a currently valid bundle context. * @param accountID the AccountID for the account whose password we're looking for.. * @return a String containing the password for the specified accountID. */ protected String loadPassword(BundleContext bundleContext, AccountID accountID) { String accountPrefix = findAccountPrefix(bundleContext, accountID, getFactoryImplPackageName()); if (accountPrefix == null) return null; CredentialsStorageService credentialsStorage = ServiceUtils.getService(bundleContext, CredentialsStorageService.class); return credentialsStorage.loadPassword(accountPrefix); } /** * Initializes and creates an account corresponding to the specified accountProperties and * registers the resulting ProtocolProvider in the <tt>context</tt> BundleContext parameter. This * method has a persistent effect. Once created the resulting account will remain installed until * removed through the uninstallAccount method. * * @param accountProperties a set of protocol (or implementation) specific properties defining the * new account. * @return the AccountID of the newly loaded account */ public AccountID loadAccount(Map<String, String> accountProperties) { AccountID accountID = createAccount(accountProperties); loadAccount(accountID); return accountID; } /** * Creates a protocol provider for the given <tt>accountID</tt> and registers it in the bundle * context. This method has a persistent effect. Once created the resulting account will remain * installed until removed through the uninstallAccount method. * * @param accountID the account identifier * @return <tt>true</tt> if the account with the given <tt>accountID</tt> is successfully loaded, * otherwise returns <tt>false</tt> */ public boolean loadAccount(AccountID accountID) { // Need to obtain the original user id property, instead of calling // accountID.getUserID(), because this method could return a modified // version of the user id property. String userID = accountID.getAccountPropertyString(ProtocolProviderFactory.USER_ID); ProtocolProviderService service = createService(userID, accountID); Dictionary<String, String> properties = new Hashtable<String, String>(); properties.put(PROTOCOL, protocolName); properties.put(USER_ID, userID); ServiceRegistration serviceRegistration = bundleContext.registerService(ProtocolProviderService.class.getName(), service, properties); if (serviceRegistration == null) return false; else { synchronized (registeredAccounts) { registeredAccounts.put(accountID, serviceRegistration); } return true; } } /** * Unloads the account corresponding to the given <tt>accountID</tt>. Unregisters the * corresponding protocol provider, but keeps the account in contrast to the uninstallAccount * method. * * @param accountID the account identifier * @return true if an account with the specified ID existed and was unloaded and false otherwise. */ public boolean unloadAccount(AccountID accountID) { // Unregister the protocol provider. ServiceReference serRef = getProviderForAccount(accountID); if (serRef == null) { return false; } BundleContext bundleContext = getBundleContext(); ProtocolProviderService protocolProvider = (ProtocolProviderService) bundleContext.getService(serRef); try { protocolProvider.unregister(); } catch (OperationFailedException ex) { logger.error( "Failed to unregister protocol provider for account : " + accountID + " caused by: " + ex); } ServiceRegistration registration; synchronized (registeredAccounts) { registration = registeredAccounts.remove(accountID); } if (registration == null) { return false; } // Kill the service. registration.unregister(); return true; } /** * Initializes and creates an account corresponding to the specified accountProperties. * * @param accountProperties a set of protocol (or implementation) specific properties defining the * new account. * @return the AccountID of the newly created account */ public AccountID createAccount(Map<String, String> accountProperties) { BundleContext bundleContext = getBundleContext(); if (bundleContext == null) throw new NullPointerException("The specified BundleContext was null"); if (accountProperties == null) throw new NullPointerException("The specified property map was null"); String userID = accountProperties.get(USER_ID); if (userID == null) throw new NullPointerException("The account properties contained no user id."); String protocolName = getProtocolName(); if (!accountProperties.containsKey(PROTOCOL)) accountProperties.put(PROTOCOL, protocolName); return createAccountID(userID, accountProperties); } /** * Creates a new <code>AccountID</code> instance with a specific user ID to represent a given set * of account properties. * * <p>The method is a pure factory allowing implementers to specify the runtime type of the * created <code>AccountID</code> and customize the instance. The returned <code>AccountID</code> * will later be associated with a <code>ProtocolProviderService</code> by the caller (e.g. using * {@link #createService(String, AccountID)}). * * @param userID the user ID of the new instance * @param accountProperties the set of properties to be represented by the new instance * @return a new <code>AccountID</code> instance with the specified user ID representing the given * set of account properties */ protected abstract AccountID createAccountID( String userID, Map<String, String> accountProperties); /** * Gets the name of the protocol this factory registers its <code>ProtocolProviderService</code>s * with and to be placed in the properties of the accounts created by this factory. * * @return the name of the protocol this factory registers its <code>ProtocolProviderService * </code>s with and to be placed in the properties of the accounts created by this factory */ public String getProtocolName() { return protocolName; } /** * Initializes a new <code>ProtocolProviderService</code> instance with a specific user ID to * represent a specific <code>AccountID</code>. * * <p>The method is a pure factory allowing implementers to specify the runtime type of the * created <code>ProtocolProviderService</code> and customize the instance. The caller will later * register the returned service with the <code>BundleContext</code> of this factory. * * @param userID the user ID to initialize the new instance with * @param accountID the <code>AccountID</code> to be represented by the new instance * @return a new <code>ProtocolProviderService</code> instance with the specific user ID * representing the specified <code>AccountID</code> */ protected abstract ProtocolProviderService createService(String userID, AccountID accountID); /** * Removes the account with <tt>accountID</tt> from the set of accounts that are persistently * stored inside the configuration service. * * @param accountID the AccountID of the account to remove. * @return true if an account has been removed and false otherwise. */ protected boolean removeStoredAccount(AccountID accountID) { return getAccountManager().removeStoredAccount(this, accountID); } /** * Returns the prefix for all persistently stored properties of the account with the specified id. * * @param bundleContext a currently valid bundle context. * @param accountID the AccountID of the account whose properties we're looking for. * @param sourcePackageName a String containing the package name of the concrete factory class * that extends us. * @return a String indicating the ConfigurationService property name prefix under which all * account properties are stored or null if no account corresponding to the specified id was * found. */ public static String findAccountPrefix( BundleContext bundleContext, AccountID accountID, String sourcePackageName) { ServiceReference confReference = bundleContext.getServiceReference(ConfigurationService.class.getName()); ConfigurationService configurationService = (ConfigurationService) bundleContext.getService(confReference); // first retrieve all accounts that we've registered List<String> storedAccounts = configurationService.getPropertyNamesByPrefix(sourcePackageName, true); // find an account with the corresponding id. for (String accountRootPropertyName : storedAccounts) { // unregister the account in the configuration service. // all the properties must have been registered in the following // hierarchy: // net.java.sip.communicator.impl.protocol.PROTO_NAME.ACC_ID.PROP_NAME String accountUID = configurationService.getString( accountRootPropertyName // node id + "." + ACCOUNT_UID); // propname if (accountID.getAccountUniqueID().equals(accountUID)) { return accountRootPropertyName; } } return null; } /** * Returns the name of the package that we're currently running in (i.e. the name of the package * containing the proto factory that extends us). * * @return a String containing the package name of the concrete factory class that extends us. */ private String getFactoryImplPackageName() { String className = getClass().getName(); return className.substring(0, className.lastIndexOf('.')); } /** Prepares the factory for bundle shutdown. */ public void stop() { if (logger.isTraceEnabled()) logger.trace("Preparing to stop all protocol providers of" + this); synchronized (registeredAccounts) { for (Enumeration<ServiceRegistration> registrations = registeredAccounts.elements(); registrations.hasMoreElements(); ) { ServiceRegistration reg = registrations.nextElement(); stop(reg); reg.unregister(); } registeredAccounts.clear(); } } /** * Shuts down the <code>ProtocolProviderService</code> representing an account registered with * this factory. * * @param registeredAccount the <code>ServiceRegistration</code> of the <code> * ProtocolProviderService</code> representing an account registered with this factory */ protected void stop(ServiceRegistration registeredAccount) { ProtocolProviderService protocolProviderService = (ProtocolProviderService) getBundleContext().getService(registeredAccount.getReference()); protocolProviderService.shutdown(); } /** * Get the <tt>AccountManager</tt> of the protocol. * * @return <tt>AccountManager</tt> of the protocol */ private AccountManager getAccountManager() { BundleContext bundleContext = getBundleContext(); ServiceReference serviceReference = bundleContext.getServiceReference(AccountManager.class.getName()); return (AccountManager) bundleContext.getService(serviceReference); } }
/** * A representation of the LogicSniffer device. * * @author J.W. Janssen */ public class LogicSnifferDevice implements Device { // CONSTANTS private static final String NAME = "OpenBench LogicSniffer"; private static final Logger LOG = Logger.getLogger(LogicSnifferDevice.class.getName()); // VARIABLES private LogicSnifferConfig config; private volatile DependencyManager dependencyManager; private volatile ManagedServiceFactory deviceProfileManagerServiceFactory; private volatile ConnectorService connectorService; private volatile StreamConnection connection; private volatile LogicSnifferConfigDialog configDialog; // METHODS public LogicSnifferConfig getConfig() { return config; } /** {@inheritDoc} */ @Override public void close() throws IOException { if (this.connection != null) { this.connection.close(); this.connection = null; } } /** {@inheritDoc} */ @Override public AcquisitionTask createAcquisitionTask(final AcquisitionProgressListener aProgressListener) throws IOException { return new LogicSnifferAcquisitionTask( this.config, getStreamConnection(), getDeviceProfileManager(), aProgressListener); } /** {@inheritDoc} */ @Override public CancelTask createCancelTask() throws IOException { if (this.config.isRleEnabled()) { return new LogicSnifferCancelTask(getStreamConnection()); } // Simply use the default behaviour... return null; } /** @see nl.lxtreme.ols.api.devices.Device#getName() */ public String getName() { return NAME; } /** @see nl.lxtreme.ols.api.devices.Device#isSetup() */ @Override public boolean isSetup() { return this.config != null; } /** * Displays the device controller dialog with enabled configuration portion and waits for user * input. * * @see nl.lxtreme.ols.api.devices.Device#setupCapture() */ @Override public boolean setupCapture(final Window aOwner) { // Just to be sure... disposeConfigDialog(); this.configDialog = new LogicSnifferConfigDialog(aOwner, this); try { boolean configConfirmed = this.configDialog.showDialog(); if (configConfirmed) { this.config = this.configDialog.getConfiguration(); } return configConfirmed; } finally { this.configDialog.dispose(); this.configDialog = null; } } /** * @param uri * @return * @throws IOException */ final StreamConnection createStreamConnection(final String uri) throws IOException { return (StreamConnection) this.connectorService.open(uri, ConnectorService.READ_WRITE, true /* timeouts */); } /** * Returns the default device profile. * * @return a default profile, never <code>null</code>. */ final DeviceProfile getDefaultProfile() { return getDeviceProfileManager().getDefaultProfile(); } /** * Returns the current device profile manager. * * @return a device profile manager, never <code>null</code>. */ final DeviceProfileManager getDeviceProfileManager() { return (DeviceProfileManager) this.deviceProfileManagerServiceFactory; } /** Called when this class is unregistered as OSGi service. */ protected void destroy(final Component aComponent) { disposeConfigDialog(); } /** * Called when this class is registered as OSGi service. * * @param aComponent the bundle context to use, cannot be <code>null</code>. */ protected void init(final Component aComponent) { final String pmFilter = String.format("(%s=%s)", Constants.SERVICE_PID, DeviceProfileManager.SERVICE_PID); aComponent // .add( this.dependencyManager .createServiceDependency() // .setService(ManagedServiceFactory.class, pmFilter) // .setAutoConfig("deviceProfileManagerServiceFactory") // .setInstanceBound(true) // .setRequired(true)) // .add( this.dependencyManager .createServiceDependency() // .setService(ConnectorService.class) // .setAutoConfig("connectorService") // .setInstanceBound(true) // .setRequired(true) // ); } /** * Disposes the current configuration dialog, if one is still visible on screen. If no * configuration dialog is visible, this method does nothing. */ private void disposeConfigDialog() { if (this.configDialog != null) { SwingComponentUtils.dispose(this.configDialog); this.configDialog = null; } } /** * Returns the current stream connection that is opened. * * @return a stream connection, can be a cached one, never <code>null</code>. * @throws IOException in case of I/O problems creating the stream connection. */ private StreamConnection getStreamConnection() throws IOException { if (this.connection == null) { final String uri = this.config.getConnectionURI(); if (LOG.isLoggable(Level.INFO)) { LOG.info("Connecting to " + uri); } this.connection = createStreamConnection(uri); } return this.connection; } }