/*
 * ident	"@(#)SARequester.java	1.2	99/05/10 SMI"
 *
 * Copyright (c) 1999 by Sun Microsystems, Inc.
 * All rights reserved.
 *
 */

//  SCCS Status:      @(#)SARequester.java	1.2	05/10/99
//  SARequester.java: Requester operations for SA.
//  Author:           James Kempf
//  Created On:       Thu Jan  8 14:59:41 1998
//  Last Modified By: James Kempf
//  Last Modified On: Thu Jan 28 15:33:33 1999
//  Update Count:     58
//

package com.sun.slp;

import java.io.*;
import java.util.*;

/**
 * The SARequester class implements the Advertiser interface.
 * It handles the request for the API. Registration is done
 * by calling into the loopback I/O so the SA server does
 * the registration.
 *
 * @version 1.2 00/10/14
 * @author Erik Guttman, James Kempf
 */


class SARequester extends Object implements Advertiser {

    // For maintaining registrations that are LIFETIME_PERMANENT.

    private static PermSARegTable pregtable = null;

    private static SLPConfig config = null;

    private Locale locale;


    SARequester(Locale nlocale) {

	Assert.nonNullParameter(nlocale, "locale");

	// Initialize...

	getPermSARegTable();

	locale = nlocale;
    }

    // Initialize config, PermSARegTable.

    static PermSARegTable getPermSARegTable() {

	if (config == null) {
	    config = SLPConfig.getSLPConfig();
	}


	if (pregtable == null) {
	    pregtable = new PermSARegTable(config);

	}

	return pregtable;
    }

    //
    // Advertiser Interface implementation.
    //

    /**
     * Return the Locator's locale object. All requests are made in
     * this locale.
     *
     * @return The Locale object.
     */

    public Locale getLocale() {
	return locale;

    }

    /**
     * Register a new service with the service location protocol in
     * the Advertiser's locale.
     *
     * @param URL	The service URL for the service.
     * @param serviceLocationAttributes A vector of ServiceLocationAttribute
     *				       objects describing the service.
     * @exception ServiceLocationException An exception is thrown if the
     *					  registration fails.
     * @exception IllegalArgumentException A  parameter is null or
     *					  otherwise invalid.
     *
     */

    public void register(ServiceURL URL,
			 Vector serviceLocationAttributes)
	throws ServiceLocationException {

	registerInternal(URL, serviceLocationAttributes, true);

    }

    /**
     * Deregister a service with the service location protocol.
     * This has the effect of deregistering the service from <b>every</b>
     * Locale and scope under which it was registered.
     *
     * @param URL	The service URL for the service.
     * @exception ServiceLocationException An exception is thrown if the
     *					  deregistration fails.
     */

    public void deregister(ServiceURL URL)
	throws ServiceLocationException {

	deregisterInternal(URL, null);

    }

    /**
     * Add attributes to a service URL in the locale of the Advertiser.
     *
     * Note that due to SLP v1 update semantics, the URL will be registered
     * if it is not already.
     *
     *
     * @param URL	The service URL for the service.
     * @param serviceLocationAttributes A vector of ServiceLocationAttribute
     *				       objects to add.
     * @exception ServiceLocationException An exception is thrown if the
     *					  operation fails.
     */

    public void addAttributes(ServiceURL URL,
			      Vector serviceLocationAttributes)
	throws ServiceLocationException {

	registerInternal(URL, serviceLocationAttributes, false);

    }

    /**
     * Delete the attributes from a service URL in the locale of
     * the Advertiser. The deletions are made for all scopes in
     * which the URL is registered.
     *
     *
     * @param URL	The service URL for the service.
     * @param attributeIds A vector of Strings indicating
     *			  the attributes to remove.
     * @exception ServiceLocationException An exception is thrown if the
     *					  operation fails.
     */

    public void deleteAttributes(ServiceURL URL,
				 Vector attributeIds)
	throws ServiceLocationException {

	if (attributeIds == null || attributeIds.size() <= 0) {
	    throw
		new IllegalArgumentException(
				config.formatMessage("null_or_empty_vector",
						     new Object[] {
				    "attributeIds"}));

	}

	deregisterInternal(URL, attributeIds);

    }

    //
    // Internal methods to do actual work.
    //

    /**
     * Takes care of registering a service.
     * @param URL    The service URL to register.
     * @param vAttrs A vector of ServiceLocationAttributes.
     * @param bFresh Informs whether this is to be a fresh registration or
     *               a reregistration.
     * @exception ServiceLocationException<br> If any errors occur during
     *		parsing out or on the remote agent.
     */

    private void registerInternal(ServiceURL URL,
				  Vector     vAttrs,
				  boolean    bFresh)
	throws ServiceLocationException {

	// Check parameters.

	Assert.nonNullParameter(URL, "URL");
	Assert.nonNullParameter(vAttrs,
				"serviceLocationAttributes");

	// Service agents are required to register in all the
	//  scopes they know.

	Vector vScopes = config.getSAConfiguredScopes();

	// Create registration message.

	CSrvReg srvreg =
	    new CSrvReg(bFresh,
			locale,
			URL,
			vScopes,
			vAttrs,
			null,
			null);

	// Register down the loopback.

	SrvLocMsg reply =
	    Transact.transactTCPMsg(config.getLoopback(), srvreg, true);

	// Handle any errors.

	handleError(reply);

	// Add registration for updating.

	// Create a reg to use for refreshing if the URL was permanently
	//  registered.

	if (URL.getIsPermanent()) {
	    CSrvReg srvReg =
		new CSrvReg(false,
			    locale,
			    URL,
			    vScopes,
			    new Vector(),
			    null,
			    null);

	    pregtable.reg(URL, srvReg);

	} else {
	    pregtable.dereg(URL);  // in case somebody registered permanent...

	}
    }



    /**
     * Takes care of deregistering a service or service attributes.
     *
     * @param URL The URL to deregister.
     * @param vAttrs The attribute tags, if any, to deregister.
     */

    private void deregisterInternal(ServiceURL URL,
				    Vector vAttrs)
	throws ServiceLocationException {

	Assert.nonNullParameter(URL, "URL");

	// Service agents are required to register in all the
	//  scopes they know.

	Vector vScopes = config.getSAConfiguredScopes();

	// If there are no attributes listed in the dereg, it removes the
	//  whole service.  In this case, purge it from the Permanent SA
	//  registration table.
	//

	if (vAttrs == null) {
	    pregtable.dereg(URL);

	}

	// Create deregistration message.

	CSrvDereg sdr =
	    new CSrvDereg(locale,
			  URL,
			  vScopes,
			  vAttrs,
			  null);

	// Register down the loopback.

	SrvLocMsg reply =
	    Transact.transactTCPMsg(config.getLoopback(), sdr, true);

	// Handle any errors.

	handleError(reply);
    }

    // Handle error returns.

    private void handleError(SrvLocMsg msg) throws ServiceLocationException {

	if (msg == null ||
	    ((msg.getHeader().functionCode == SrvLocHeader.SrvAck) == false)) {
	    throw new ServiceLocationException(
				ServiceLocationException.NETWORK_ERROR,
				"unexpected_ipc",
				new Object[0]);
	} else {
	    short ex =
		msg.getErrorCode();

	    if (ex != ServiceLocationException.OK) {
		throw new ServiceLocationException(ex,
						   "remote_error",
						   new Object[0]);
	    }
	}
    }

}
