/*************************************************************************
*
* $RCSfile: XmlSearchServiceImpl.java,v $
*
* $Revision: 1.1 $
*
* last change: $Author: abi $ $Date: 2000/11/30 18:03:51 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (the "License"); You may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at http://www.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
package com.sun.xmlsearch.xml.qe;
import java.io.IOException;
import java.io.File;
import java.util.*;
import java.net.URL;
import java.net.MalformedURLException;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import com.sun.jini.lease.LeaseRenewalManager;
import com.sun.jini.lookup.JoinManager;
import com.sun.jini.lookup.ServiceIDListener;
import com.sun.jini.lookup.entry.BasicServiceType;
import com.sun.jini.admin.DestroyAdmin;
import net.jini.core.entry.Entry;
import net.jini.lookup.entry.Name;
import net.jini.lookup.entry.ServiceInfo;
import net.jini.core.lookup.ServiceID;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.discovery.LookupLocator;
import net.jini.admin.Administrable;
import net.jini.discovery.DiscoveryListener;
import com.sun.jini.discovery.LookupLocatorDiscovery;
import net.jini.discovery.LookupDiscovery;
import net.jini.discovery.DiscoveryEvent;
import org.w3c.dom.*;
import com.sun.xmlsearch.util.Configuration;
public final class XmlSearchServiceImpl implements XmlSearchService {
private static final String PRODUCT = "XmlSearchService";
private static final String MANUFACTURER = "Sun Microsystems, Inc.";
private static final String VENDOR = MANUFACTURER;
private static final String VERSION = "1.0";
private String[] _groupsToJoin;
private JoinManager _joinMgr;
private static final int DefaultLookupPortNumber = 4160;
private ServiceID _serviceID;
private Entry[] _serviceAttrs;
private String _attributeString;
public static ServiceRegistrar _lookupSrvc = null;
private LookupLocator[] _lookupLocators;
private LookupDiscovery _lookupDiscovery;
public static ArrayList _lookupInfoList = new ArrayList();
private Hashtable _servers = new Hashtable();
private String _name = "JavadocXML";
public Object getAdmin() throws RemoteException {
return new XmlSearchServiceAdmin(this);
}
private void processServiceRegistration(Element el) throws Exception {
_name = el.getAttribute("name");
if (_name == null || _name.length() == 0)
_name = "XMLSearchService";
NodeList list = el.getElementsByTagName("ServiceRegistration");
if (list.getLength() == 1) {
Element srEl = (Element)list.item(0);
String group = srEl.getAttribute("group");
if (group == null)
group = "XmlSearch";
System.out.println("will join group: " + group);
_groupsToJoin = new String[] { group };
NodeList lookups = srEl.getElementsByTagName("Lookup");
int nLookups = lookups.getLength();
if (nLookups > 0) {
_lookupLocators = new LookupLocator[nLookups];
for (int i = 0; i < nLookups; i++) {
Element lookupEl = (Element)lookups.item(i);
String port = lookupEl.getAttribute("port");
int portNumber = port != null && port.length() > 0
? Integer.parseInt(port)
: DefaultLookupPortNumber;
String host = lookupEl.getAttribute("host");
_lookupLocators[i] =
new LookupLocator("jini://"+host+':'+portNumber+'/');
System.out.println("lookup locator: " + _lookupLocators[i]);
}
}
}
NodeList servers = el.getElementsByTagName("XmlSearchServer");
for (int i = 0; i < servers.getLength(); i++) {
final Element srEl = (Element)servers.item(i);
addServer(new XmlSearchServerImpl(srEl));
}
}
private void addServer(XmlSearchServer server) throws Exception {
_servers.put(server.getName(), server);
}
private XmlSearchServiceImpl() throws RemoteException {
super();
UnicastRemoteObject.exportObject(this);
}
public void startXmlSearchServers(byte[] xmlConfig) {
try {
Element config = Configuration.parse(xmlConfig);
NodeList servers = config.getElementsByTagName("XmlSearchServer");
for (int i = 0; i < servers.getLength(); i++)
installServer((Element)servers.item(i));
}
catch (Exception e) {
e.printStackTrace();
}
}
private void installServer(Element config) throws Exception {
final XmlSearchServer server = new XmlSearchServerImpl(config);
final String serverName = server.getName();
if (_servers.get(serverName) == null)
_joinMgr.addAttributes(new Entry[] {
new SearchEngineEntry(server)
});
else
_joinMgr.modifyAttributes(
new Entry[] {
new SearchEngineEntry(serverName)
},
new Entry[] {
new SearchEngineEntry(server)
}
);
addServer(server);
}
public static void main(String[] args) {
try {
Element config = Configuration.configElementFromArgs(args);
if (config != null) {
XmlSearchServiceImpl server = new XmlSearchServiceImpl();
server.processServiceRegistration(config);
server.setup();
}
else
System.exit(1);
}
catch (Exception e) {
e.printStackTrace();
}
}
private void setup() {
if (_lookupSrvc == null) // first time
System.setSecurityManager(new RMISecurityManager());
/* ----------------------------------------------------------------- */
/* ----------------------------------------------------------------- */
/* ----------------------------------------------------------------- */
/* ----------------------------------------------------------------- */
/* Use LookupLocatorDiscovery to find a Lookup Service */
if (_lookupSrvc == null) { // first time
// Use LookupDiscovery to find a Lookup Service
try {
System.out.println("LookupDiscovery for " + _groupsToJoin[0]);
_lookupDiscovery = new LookupDiscovery(_groupsToJoin);
}
catch (IOException e) {
System.out.println("IOException from LookupDiscovery constructor");
}
_lookupDiscovery
.addDiscoveryListener(new
LookupDiscoveryListener(_groupsToJoin));
}
startService();
}
public void setServiceID(ServiceID id) {
_serviceID = id;
}
public void close() {
(new Thread() {
public void run(){
try {
_joinMgr.terminate();
_joinMgr = null;
System.exit(0);
}
catch (Exception e) {
System.err.println(e);
}
}}).start();
}
private void startService() {
Vector entries = new Vector();
entries.addElement(new ServiceInfo(PRODUCT, MANUFACTURER,
VENDOR, VERSION, null, null));
entries.addElement(new BasicServiceType("XmlSearchService"));
entries.addElement(new Name(_name));
Enumeration servers = _servers.elements();
while (servers.hasMoreElements()) {
XmlSearchServer server = (XmlSearchServer)servers.nextElement();
entries.addElement(new SearchEngineEntry(server));
}
_serviceAttrs = new Entry[entries.size()];
entries.toArray(_serviceAttrs);
/* Create a LeaseRenewalManager for the JoinManager to use */
LeaseRenewalManager leaseRenewalMgr = new LeaseRenewalManager();
try {
_joinMgr = new JoinManager(this,
_serviceAttrs,
_groupsToJoin,
_lookupLocators,
new ServiceIDListenerImpl(this),
leaseRenewalMgr);
} catch (IOException e) {
System.out.println("IOException from JoinManager constructor");
e.printStackTrace();
}
}
/** Class which listens for the announcement of a service ID assignment
* by the JoinManager
*/
private class ServiceIDListenerImpl implements ServiceIDListener {
private final XmlSearchServiceImpl _server;
public ServiceIDListenerImpl(XmlSearchServiceImpl server) {
super();
_server = server;
}
/** The JoinManager will invoke this method when it receives a
* valid ServiceID from a lookup service; passing in that
* ServiceID so that it may be stored for persistence.
*/
public void serviceIDNotify(ServiceID serviceID) {
System.out.println("\nRegistered ServiceID: " +serviceID.toString());
_server.setServiceID(serviceID);
}
}
private final class LookupDiscoveryListener implements DiscoveryListener {
private String[] groupsWanted;
public LookupDiscoveryListener(String[] groupsWanted) {
super();
this.groupsWanted = groupsWanted;
}
public void discovered(DiscoveryEvent evnt) {
System.out.println("LookupDiscoveryListener: discovered...");
ServiceRegistrar[] regs = evnt.getRegistrars();
/* Note: the tendancy here is to immediately try to interact
* with the discovered lookup service (such as query
* the lookup for services). But such interaction should
* take place in a separate thread because a method
* invocation on the lookup service is a remote invocation;
* which may prevent/impede the LookupDiscovery class,
* which invokes this method, from returning to its
* primary duty of discovering other lookups.
*
* Thus, create and start a thread that will store the
* information about the lookup(s) just discovered so that
* this method may return; and the the LookupDiscovery
* object may resume its duties.
*/
Thread storeThread = new StoreLookupInfoThread(regs, groupsWanted);
storeThread.start();
}
public void discarded(DiscoveryEvent evnt) {
/* Note: once a lookup service is discovered, there is no on-going
* communication between LookupDiscovery and a discovered
* lookup service. This means that if a lookup service goes
* away, there will be no automatic notification that such
* an event has occurred.
*
* Thus, if a client or service attempts to use a lookup
* service but receives a RemoteException as a result of
* that attempt, it is the responsibility of the client or
* service to invoke the discard method of the
* LookupDiscovery object instantiated by the client or
* service. Doing so will flush the lookup service from the
* LookupDiscovery object's cache; causing this method
* to be invoked.
*/
System.out.println("LookupDiscoveryListener: discarded ...");
/* Retrieve the discarded lookup service(s) from the event */
ServiceRegistrar[] regs = evnt.getRegistrars();
for (int i = 0; i < regs.length; i++) {
System.out.println(" Discarded Lookup: "+regs[i]);
}
}
}
/** Thread in which information about the discovered lookup service
* is stored for later use.
*
* A new instance of this thread is created each time a new lookup
* belonging to a group-of-interest is discovered. Performing the
* storage duties in a separate thread will allow the discovery
* thread to return to its primary duties more quickly.
*
* Upon completion of the storage process, this thread will exit.
*/
private final class StoreLookupInfoThread extends Thread {
private static final String PUBLIC_GROUP = "";
private ServiceRegistrar[] regs;
private String[] groupsWanted;
public StoreLookupInfoThread(ServiceRegistrar[] regs,
String[] groupsWanted)
{
super("storeLookupInfoThread");
// setDaemon(true);
this.regs = regs;
this.groupsWanted = groupsWanted;
}
public void run() {
for (int i=0; i < regs.length; i++) {
try {
try {
/* Retrieve the groups of all the discovered lookups */
String[] regGroups = regs[i].getGroups();
LookupLocator loc = regs[i].getLocator();
_lookupSrvc = regs[i];
String loc_str = loc.toString();
Vector groupsVec = new Vector();
/* Look for only lookups in groups that were input */
System.out.println(" Lookup on host "+loc_str+":");
System.out.println("regGroups.length = " + regGroups.length);
for(int j=0; j<regGroups.length; j++) {
if(regGroups[j].compareTo(PUBLIC_GROUP) == 0) {
System.out.println
(" belongs to Group: public");
} else {
System.out.println(" belongs to Group: "+regGroups[j]);
}
if(groupsWanted != null) {
for(int k=0; k<groupsWanted.length; k++) {
if(regGroups[j].compareTo
(groupsWanted[k]) == 0)
{
groupsVec.add(regGroups[j]);
}
}
} else {
groupsVec.add(regGroups[j]);
}
}
int nGroups = groupsVec.size();
if( nGroups > 0 || true) {
synchronized (_lookupInfoList) {
_lookupInfoList.add
(new LookupInfo(regs[i],loc_str,
(String[])groupsVec.toArray
(new String[nGroups])));
}
}
int nLookups = _lookupInfoList.size();
System.out.println("nLookups = " + nLookups);
} catch (java.security.AccessControlException e) {
/* Connection Disallowed */
System.out.println
(" Security Restriction: Policy"
+" file of discovered Lookup"
+"\n "
+" does not allow service registrations,"
+"\n "
+" service lookups, or other remote"
+"\n "
+" invocations from the current host");
}
} catch (RemoteException e) {
System.out.println
("RemoteException on call to getLocator() "+e.toString());
}
}
}
}
private final class LookupInfo {
public ServiceRegistrar _lookupSrvc;
public String _hostname;
public String[] _groups;
public LookupInfo(ServiceRegistrar lookupSrvc,
String hostname,
String[] groups) {
_lookupSrvc = lookupSrvc;
_hostname = hostname;
_groups = groups;
}
}
}