Package org.vfny.geoserver.zserver

Source Code of org.vfny.geoserver.zserver.GeoZServerAssociation

//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; either version 2.1 of
// the license, or (at your option) any later version.
//
// This program 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 program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite
// 330, Boston, MA  02111-1307, USA.
//
package org.vfny.geoserver.zserver;

import java.math.BigInteger;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Logger;

import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;

import com.k_int.IR.IRQuery;
import com.k_int.IR.InformationFragment;
import com.k_int.IR.PresentException;
import com.k_int.IR.RecordFormatSpecification;
import com.k_int.IR.ScanException;
import com.k_int.IR.ScanInformation;
import com.k_int.IR.ScanRequestInfo;
import com.k_int.IR.Scanable;
import com.k_int.IR.SearchException;
import com.k_int.IR.SearchTask;
import com.k_int.IR.Searchable;
import com.k_int.IR.TimeoutExceededException;
import com.k_int.codec.util.OIDRegister;
import com.k_int.codec.util.OIDRegisterEntry;
import com.k_int.gen.AsnUseful.EXTERNAL_type;
import com.k_int.gen.AsnUseful.encoding_inline0_type;
import com.k_int.gen.NegotiationRecordDefinition_charSetandLanguageNegotiation_3.CharSetandLanguageNegotiation_type;
import com.k_int.gen.NegotiationRecordDefinition_charSetandLanguageNegotiation_3.Iso10646_type;
import com.k_int.gen.NegotiationRecordDefinition_charSetandLanguageNegotiation_3.OriginProposal_type;
import com.k_int.gen.NegotiationRecordDefinition_charSetandLanguageNegotiation_3.proposedCharSets_inline0_choice1_type;
import com.k_int.gen.Z39_50_APDU_1995.DefaultDiagFormat_type;
import com.k_int.gen.Z39_50_APDU_1995.DeleteResultSetRequest_type;
import com.k_int.gen.Z39_50_APDU_1995.DeleteResultSetResponse_type;
import com.k_int.gen.Z39_50_APDU_1995.ElementSetNames_type;
import com.k_int.gen.Z39_50_APDU_1995.InitializeRequest_type;
import com.k_int.gen.Z39_50_APDU_1995.NamePlusRecord_type;
import com.k_int.gen.Z39_50_APDU_1995.OtherInformationItem43_type;
import com.k_int.gen.Z39_50_APDU_1995.PDU_type;
import com.k_int.gen.Z39_50_APDU_1995.PresentRequest_type;
import com.k_int.gen.Z39_50_APDU_1995.PresentResponse_type;
import com.k_int.gen.Z39_50_APDU_1995.Query_type;
import com.k_int.gen.Z39_50_APDU_1995.RPNQuery_type;
import com.k_int.gen.Z39_50_APDU_1995.Records_type;
import com.k_int.gen.Z39_50_APDU_1995.ScanRequest_type;
import com.k_int.gen.Z39_50_APDU_1995.SearchRequest_type;
import com.k_int.gen.Z39_50_APDU_1995.SearchResponse_type;
import com.k_int.gen.Z39_50_APDU_1995.addinfo_inline14_type;
import com.k_int.gen.Z39_50_APDU_1995.information_inline45_type;
import com.k_int.gen.Z39_50_APDU_1995.record_inline13_type;
import com.k_int.util.RPNQueryRep.RootNode;
import com.k_int.z3950.util.APDUEvent;
import com.k_int.z3950.util.GenericEventToTargetListenerAdapter;
import com.k_int.z3950.util.TargetAPDUListener;
import com.k_int.z3950.util.Z3950Constants;
import com.k_int.z3950.util.ZTargetEndpoint;


/**
* GeoZServerAssociation backend Z3950 association. Code based on
* ZServerAssociation, in jzkit source tree:
*
* @author:     Ian Ibbotson (ibbo@k-int.com) Company:     KI This class
*         handles a connection, handling the init, search and present
*         requests.
* @author Chris Holmes, TOPP
* @version $Id: GeoZServerAssociation.java,v 1.8 2004/01/31 00:27:24 jive Exp $
* @task TODO: change this so it extends ZServerAssociation, instead of r
* ewriting things, as there are many methods used which were not changed. 
* Also, unit tests, but you'd need a client or else sample encoded z3950 requests.
*/
public class GeoZServerAssociation implements TargetAPDUListener {
    /** Standard logging instance for class */
    private static final Logger LOGGER = Logger.getLogger(
            "org.vfny.geoserver.zserver");

    /** to generate search tasks. */
    private Searchable search_service = null;

    /** how this attaches to the socket. */
    private ZTargetEndpoint assoc = null;

    /** The names of the searches run by this client. */
    private Hashtable active_searches = new Hashtable();

    /* Impl notes: Used
     * mostly by Present request, because z3950 is stateful,
     * so it needs to know what searches it has run, so
     * it can return more specific records.*/

    /** Handles the translation of Object IDs into their names. */
    private OIDRegister reg = OIDRegister.getRegister();

    /*  Impl: z3950 specifies that most everything, such as attributes,
     * relations, return formats and more, are sent with an ID.  The
     * list of ids is at: http://www.loc.gov/z3950/agency/defns/oids.html.
     * jzkit uses this OIDRegister to do the translations.  The a2jruntime
     * should hold all the information to propertly fill the OIDRegister
     * with appropriate information.
     */

    /** for notification messages when requests come in. */
    private GenericEventToTargetListenerAdapter event_adapter = null;

    /**
     * the properties needed to do a search, such as where the  datafolders
     * live, as well as where the attribute mappings and index live
     */
    private Properties serverProps;

    public GeoZServerAssociation(Socket s, Properties p) {
        //TODO: put this in nicer place...this is just a hack to get old html
        //oid working...should do something like Isite where it translates
        //old oids into the new ones.
        OIDRegisterEntry html = new OIDRegisterEntry("html",
                "{1,2,840,10003,5,1000,34,1}", "record format", null);
        reg.register_oid(html);

        //to generate search tasks.
        this.search_service = (Searchable) new GeoSearchable();
        serverProps = p;
        search_service.init(p);

        //set up the socket and enable listening.
        assoc = new ZTargetEndpoint(s);
        event_adapter = new GenericEventToTargetListenerAdapter(this);
        assoc.getPDUAnnouncer().addObserver(event_adapter);
        assoc.start();
    }

    /**
     * Handles the incoming Init Requset.
     *
     * @param e the event that holds the pdu of the request.
     */
    public void incomingInitRequest(APDUEvent e) {
        LOGGER.finer("Incoming initRequest....");

        /* Impl notes: So the way jzkit works is with this a2j method,
         * asn to java.  It can run automatically which is nice, but
         * the objects it generates are a little different.  Basically the
         * asn for z3950 is a specification of the various requests, what
         * exactly they are.  It looks like this:
         * SearchRequest ::= SEQUENCE{
         * referenceId          ReferenceId OPTIONAL,
         * smallSetUpperBound    [13]  IMPLICIT INTEGER,
         * replaceIndicator      [16]  IMPLICIT BOOLEAN,
         * resultSetName      [17]  IMPLICIT InternationalString,
         * etc...  The way jzkit deals with this is that a2j generates
         * a bunch of classes, so there is a searchRequest_type and
         * searchRequest_codec class.  The type is the useful one, where
         * one can actually work with it.  Most of it makes sense, but
         * one confusing part is the choice object.  Many of the classes
         * are derived from it, and basically they have two important
         * fields, which and o.  Which says which of the choices is stored
         * in the class, and o is the Object of that choice.  So to figure
         * out what's in a class, you need to first use which, and then
         * access the object stored based on the which value.  Yeah, it's
         * pretty obscure, and jzkit documentation is not that good.  But
         * read through the code and it might make a little more sense.  I'll
         * try to point out a few examples. */
        InitializeRequest_type init_request = (InitializeRequest_type) (e
            .getPDU().o);

        /* Like here, we have to cast the object held in the PDU to the
         * InitializeRequest_type class, so we can use it.*/
        for (int i = 0; i < Z3950Constants.z3950_option_names.length; i++) {
            if (init_request.options.isSet(i)) {
                LOGGER.finer("Origin requested service: "
                    + Z3950Constants.z3950_option_names[i]);
            }
        }

        // Did the origin request scan?
        if (init_request.options.isSet(7)) {
            //the geo profile does not require support of scan.
            init_request.options.clearBit(7);
            LOGGER.finer("Origin requested scan, not supported by"
                + "this backend realisation.");
        }

        // If we are talking v2, userInformationField may contain
        //a character Set Negotiation field, if v3,
        //otherInfo may contain a charset/language negotiation feature.
        if (init_request.userInformationField != null) {
            OIDRegisterEntry ent = reg.lookupByOID(init_request.userInformationField.direct_reference);

            if (ent != null) {
                LOGGER.finer("Init Request contains userInformationField oid="
                    + ent.getName());
            } else {
                LOGGER.finer("Unkown external in userInformationField");
            }

            // The OID for the external should be found
            //in userInformationField.direct_reference
        }

        if (init_request.otherInfo != null) {
            LOGGER.finer("Init Request contains otherInfo entries");

            for (Enumeration other_info_enum = init_request.otherInfo.elements();
                    other_info_enum.hasMoreElements();) {
                LOGGER.finer("Processing otherInfo entry...");

                // Process the external at other_info_enum.nextElement();
                OtherInformationItem43_type oit = (OtherInformationItem43_type) (other_info_enum
                    .nextElement());

                LOGGER.finer("Processing OtherInformationItem43_type");

                switch (oit.information.which) {
                case information_inline45_type.externallydefinedinfo_CID:

                    EXTERNAL_type et = (EXTERNAL_type) (oit.information.o);

                    if (et.direct_reference != null) {
                        OIDRegisterEntry ent = reg.lookupByOID(et.direct_reference);
                        LOGGER.finer("External with direct reference, oid="
                            + ent.getName());

                        // Are we dealing with character set negotiation.
                        if (ent.getName().equals("z_charset_neg_3")) {
                            handleNLSNegotiation((CharSetandLanguageNegotiation_type) (et.encoding.o));
                        }
                    }

                    break;

                default:
                    LOGGER.finer("Currently unhandled OtherInformationType");

                    break;
                }
            }
        }

        try {
            assoc.sendInitResponse(init_request.referenceId,
                init_request.protocolVersion, init_request.options,
                init_request.preferredMessageSize.longValue(),
                init_request.exceptionalRecordSize.longValue(), true, "174",
                "TOPP Geoserver zserver module", "GeoServer 0.93", null, null);
        } catch (java.io.IOException ioe) {
            ioe.printStackTrace();
        }
    }

    /**
     * Handles the language and charset negotiation.
     *
     * @param neg the negotiation type object.
     */
    private void handleNLSNegotiation(CharSetandLanguageNegotiation_type neg) {
        LOGGER.finer("Handle Character Set and Language Negotiation");

        if (neg.which == CharSetandLanguageNegotiation_type.proposal_CID) {
            OriginProposal_type op = (OriginProposal_type) (neg.o);

            // Deal with any proposed character sets.
            if (op.proposedCharSets != null) {
                for (Enumeration prop_charsets = op.proposedCharSets.elements();
                        prop_charsets.hasMoreElements();) {
                    proposedCharSets_inline0_choice1_type c = (proposedCharSets_inline0_choice1_type) (prop_charsets
                        .nextElement());

                    switch (c.which) {
                    case proposedCharSets_inline0_choice1_type.iso10646_CID:

                        // The client proposes an iso 10646 id for a character set
                        Iso10646_type iso_type = (Iso10646_type) (c.o);
                        OIDRegisterEntry ent = reg.lookupByOID(iso_type.encodingLevel);
                        LOGGER.finer("Client proposes iso10646 charset: "
                            + ent.getName());

                        break;

                    default:
                        LOGGER.warning("Unhandled character set encoding");

                        break;
                    }
                }
            }
        }
    }

    /**
     * Handles the incoming Search Requset.
     *
     * @param e the event that holds the pdu of the request.
     */
    public void incomingSearchRequest(APDUEvent e) {
        LOGGER.finer("Processing incomingSearch_Request");

        SearchRequest_type search_request = (SearchRequest_type) (e.getPDU().o);

        // Create a search response
        PDU_type pdu = new PDU_type();
        pdu.which = PDU_type.searchresponse_CID;

        SearchResponse_type response = new SearchResponse_type();
        pdu.o = response;

        int ssub = search_request.smallSetUpperBound.intValue();
        int lslb = search_request.largeSetLowerBound.intValue();
        int mspn = search_request.mediumSetPresentNumber.intValue();

        LOGGER.finer("ssub = " + ssub + " lslb = " + lslb + " mspn = " + mspn);

        response.referenceId = search_request.referenceId;

        // Assume failure unless something below sets to true
        response.searchStatus = Boolean.FALSE;

        RootNode rn = null;

        try {
            switch (search_request.query.which) {
            case Query_type.type_0_CID:
                LOGGER.finer("Processing Any Query");

                // Any
                break;

            case Query_type.type_1_CID:
            case Query_type.type_101_CID:

                // RPN query
                LOGGER.finer("Processing RPN Query");
                rn = com.k_int.z3950.util.RPN2Internal.zRPNStructure2RootNode((RPNQuery_type) (search_request.query.o));

                break;

            case Query_type.type_2_CID:
            case Query_type.type_100_CID:
            case Query_type.type_102_CID:
                LOGGER.finer("Processing OctetString Query");

                // Octet String
                break;
            }

            if (rn != null) {
                LOGGER.finer("Got root node");

                IRQuery q = new IRQuery();
                q.collections = search_request.databaseNames;
                q.query = new com.k_int.IR.QueryModels.RPNTree(rn);

                // Process the query
                LOGGER.finer("Create Search Task with query:" + q);

                SearchTask st = search_service.createTask(q,
                        search_request.referenceId);

                // Evaluate the query, waiting 10 seconds for the task to complete.
                //We really want to be
                // able to pass in a predicate to wait for here,
                //e.g. evaluate(10000, "NumHits > 100 OR Status=Complete");
                LOGGER.finer("Evaluate Search Task");

                try {
                    st.evaluate(10000);
                } catch (TimeoutExceededException tee) {
                    LOGGER.finer(
                        "Timeout exceeded waiting for search to complete");
                }

                if (search_request.resultSetName != null) {
                    LOGGER.finer("putting st with name "
                        + search_request.resultSetName);
                    active_searches.put(search_request.resultSetName, st);
                }

                active_searches.put("Default", st);

                // Result records processing
                int result_count = st.getTaskResultSet().getFragmentCount();
                LOGGER.finer("result count is " + result_count);

                // Number of hits
                response.resultCount = BigInteger.valueOf(result_count);

                // Figure out Search Status
                if ((st.getTaskStatusCode() != SearchTask.TASK_FAILURE)) {
                    response.searchStatus = Boolean.TRUE;
                } else {
                    // Figure out Result Set Status
                    switch (st.getTaskStatusCode()) {
                    //case SearchTask.TASK_EXECUTING_ASYNC:
                    case SearchTask.TASK_EXECUTING:

                        // resultSetStatus = 2 (interim) Partial results available,
                        //not necessarily valid
                        response.resultSetStatus = BigInteger.valueOf(2);

                        break;

                    case SearchTask.TASK_FAILURE:

                        // resultSetStatus = 3 (none) No result set
                        response.resultSetStatus = BigInteger.valueOf(3);

                        break;
                    }
                }

                LOGGER.finer("Is " + result_count + " <= " + lslb + " or <= "
                    + ssub);

                if ((result_count <= lslb) || (result_count <= ssub)) {
                    LOGGER.finer("Yep");

                    int start = 1;
                    int count = ((result_count <= ssub) ? result_count : mspn);

                    if (count > 0) {
                        LOGGER.finer("Asking for " + count
                            + " response records from " + start);
                        LOGGER.finer("Search request default = "
                            + search_request.preferredRecordSyntax);
                        response.records = createRecordsFor(st,
                                search_request.preferredRecordSyntax, start,
                                count, GeoProfile.BREIF_SET);

                        if (response.records.which == Records_type.responserecords_CID) {
                            LOGGER.finer("We have records");

                            // Looks like we managed to present some records OK..
                            response.numberOfRecordsReturned = BigInteger
                                .valueOf(((Vector) (response.records.o)).size());
                            response.nextResultSetPosition = BigInteger.valueOf(count
                                    + 1);
                            response.presentStatus = BigInteger.valueOf(0);
                        } else { // Non surrogate diagnostics ( Single or Multiple )
                            LOGGER.finer("Diagnostics");
                            response.presentStatus = BigInteger.valueOf(5);
                            response.numberOfRecordsReturned = BigInteger
                                .valueOf(0);
                            response.nextResultSetPosition = BigInteger.valueOf(1);
                        }
                    } else {
                        LOGGER.finer("No need to piggyback records....");
                        response.numberOfRecordsReturned = BigInteger.valueOf(0);
                        response.nextResultSetPosition = BigInteger.valueOf(1);
                        response.presentStatus = BigInteger.valueOf(0);
                    }
                } else {
                    response.presentStatus = BigInteger.valueOf(5);
                    response.numberOfRecordsReturned = BigInteger.valueOf(0);
                    response.nextResultSetPosition = BigInteger.valueOf(1);
                }
            } else {
                LOGGER.finer("Unable to process query into root node");
            }
        } catch (com.k_int.IR.InvalidQueryException iqe) {
            // Need to send a diagnostic
            iqe.printStackTrace();
            response.resultCount = BigInteger.valueOf(0);
            response.presentStatus = BigInteger.valueOf(5); // Failure
            response.numberOfRecordsReturned = BigInteger.valueOf(0);
            response.nextResultSetPosition = BigInteger.valueOf(0);
            response.resultSetStatus = BigInteger.valueOf(3);

            // No result set available
            response.records = createNSD(null, iqe.toString());
        } catch (SearchException se) {
            // We need to populate a diagnostic here
            LOGGER.finer("Search returning diagnostic. Reason:" + se.toString());
            se.printStackTrace();
            response.resultCount = BigInteger.valueOf(0);
            response.presentStatus = BigInteger.valueOf(5); // Failure
            response.numberOfRecordsReturned = BigInteger.valueOf(0);
            response.nextResultSetPosition = BigInteger.valueOf(0);
            response.resultSetStatus = BigInteger.valueOf(3);

            // No result set available
            response.records = createNSD((String) (se.additional), se.toString());
        }

        LOGGER.finer("Send search response : ");

        try {
            assoc.encodeAndSend(pdu);
        } catch (java.io.IOException ioe) {
            ioe.printStackTrace();
        }
    }

    public void incomingPresentRequest(APDUEvent e) {
        LOGGER.finer("Incoming present_Request");

        PresentRequest_type present_request = (PresentRequest_type) (e.getPDU().o);

        String requested_element_set = (String) ((ElementSetNames_type) present_request.recordComposition.o).o;

        if (requested_element_set == null) {
            //default to full record.
            requested_element_set = GeoProfile.FULL_SET;
        }

        // Create a present response
        PDU_type pdu = new PDU_type();
        pdu.which = PDU_type.presentresponse_CID;

        PresentResponse_type response = new PresentResponse_type();
        pdu.o = response;
        response.referenceId = present_request.referenceId;
        response.otherInfo = null;

        SearchTask st = (SearchTask) (active_searches.get(present_request.resultSetId));

        if (st == null) {
            st = (SearchTask) (active_searches.get("Default"));
        }

        //the last search done is always stored in the hashtable
        //with both the resultSetName of the searchRequest and the value "Default"
        //So if the resultSetId can't be found the last search task is used.
        int start = present_request.resultSetStartPoint.intValue();
        int count = present_request.numberOfRecordsRequested.intValue();

        response.records = createRecordsFor(st,
                present_request.preferredRecordSyntax, start, count,
                requested_element_set);

        if (response.records.which == Records_type.responserecords_CID) {
            // Looks like we managed to present some records OK..
            response.numberOfRecordsReturned = BigInteger.valueOf(((Vector) (response.records.o))
                    .size());

            if ((start + count) >= st.getTaskResultSet().getFragmentCount()) {
                response.nextResultSetPosition = BigInteger.valueOf(0);
            } else {
                response.nextResultSetPosition = BigInteger.valueOf(start
                        + count);
            }

            response.presentStatus = BigInteger.valueOf(0);
        } else { // Non surrogate diagnostics ( Single or Multiple )
            response.numberOfRecordsReturned = BigInteger.valueOf(0);
            response.nextResultSetPosition = present_request.resultSetStartPoint;

            response.presentStatus = BigInteger.valueOf(5);
        }

        try {
            assoc.encodeAndSend(pdu);
        } catch (java.io.IOException ioe) {
            ioe.printStackTrace();
        }
    }

    /**
     * This will not be in final GeoZServerAssociation, just use
     * ZServerAssociation, when we are a child of it.
     *
     * @param e DOCUMENT ME!
     */
    public void incomingDeleteResultSetRequest(APDUEvent e) {
        LOGGER.finer("Incoming deleteResultSetRequest");

        DeleteResultSetRequest_type delete_request = (DeleteResultSetRequest_type) (e
            .getPDU().o);

        // Create a DeleteResultSetResponse
        PDU_type pdu = new PDU_type();
        pdu.which = PDU_type.deleteresultsetresponse_CID;

        DeleteResultSetResponse_type response = new DeleteResultSetResponse_type();
        pdu.o = response;
        response.referenceId = delete_request.referenceId;

        if (delete_request.deleteFunction.intValue() == 0) {
            // Delete the result sets identified by
            //delete_request.resultSetList
            for (Enumeration task_list = delete_request.resultSetList.elements();
                    task_list.hasMoreElements();) {
                String next_rs = (String) task_list.nextElement();
                active_searches.remove(next_rs);

                // search_service.deleteTask(st.getTaskIdentifier());
            }
        } else {
            // Function must be 1 : All sets in the association
            active_searches.clear();
        }

        response.deleteOperationStatus = BigInteger.valueOf(0); // 0 = Success,

        try {
            assoc.encodeAndSend(pdu);
        } catch (java.io.IOException ioe) {
            ioe.printStackTrace();
        }
    }

    /**
     * closes the client's connection.
     */
    public void incomingClose(APDUEvent e) {
        LOGGER.finer("Close...");
        assoc.getPDUAnnouncer().deleteObserver(event_adapter);
        assoc.getPDUAnnouncer().deleteObservers();
        event_adapter = null;
        assoc.shutdown();

        try {
            assoc.join();
        } catch (java.lang.InterruptedException ie) {
        }

        LOGGER.finer("Done joining with assoc thread");

        LOGGER.finer("Deleting tasks...");

        // Blow away any active search tasks. When these tasks finalize,
        // they should make
        // sure they release any resources held by the creating Searchable object
        active_searches.clear();
        search_service.destroy();
        search_service = null;

        assoc = null;
    }

    /**
     * Retrieves the record from the search task and encodes it to send.
     *
     * @param st The search task that holds the records.
     * @param preferredRecordSyntax the OID of the syntax.
     * @param start the number of the first record to return.
     * @param count the number of records to return.
     * @param recordFormatSetname the size of the set.
     */
    Records_type createRecordsFor(SearchTask st, int[] preferredRecordSyntax,
        int start, int count, String recordFormatSetname) {
        Records_type retval = new Records_type();

        LOGGER.finer("createRecordsFor(st, " + start + "," + count + ")");
        LOGGER.finer("pref rec syn = " + preferredRecordSyntax);
        LOGGER.finer("record setname = " + recordFormatSetname);
        LOGGER.finer("search task = " + st);

        // Try and do a normal present
        try {
            if (start < 1) {
                throw new PresentException("Start record must be > 0", "13");
            }

            int numRecs = st.getTaskResultSet().getFragmentCount();

            LOGGER.finer("numresults = " + numRecs);

            int requestedNum = (start + count) - 1;

            if (requestedNum > numRecs) {
                count = numRecs - (start - 1);

                if (((start + count) - 1) > numRecs) {
                    LOGGER.finer(requestedNum + " < " + numRecs);
                    throw new PresentException("Start+Count-1 (" + requestedNum
                        + ") must be < the "
                        + " number of items in the result set: " + numRecs, "13");
                }
            }

            if (st == null) {
                throw new PresentException("Unable to locate result set", "30");
            }

            Vector v = new Vector();
            retval.which = Records_type.responserecords_CID;
            retval.o = v;

            OIDRegisterEntry requested_syntax = null;
            String requested_syntax_name = null;

            if (preferredRecordSyntax != null) {
                requested_syntax = reg.lookupByOID(preferredRecordSyntax);

                if (requested_syntax == null) { // unsupported record syntax

                    StringBuffer oid = new StringBuffer();

                    for (int i = 0; i < preferredRecordSyntax.length; i++) {
                        if (i != 0) {
                            oid.append('.');
                        }

                        oid.append(preferredRecordSyntax[i]);
                    }

                    LOGGER.warning("Unsupported preferredRecordSyntax="
                        + oid.toString());

                    // Need to set up diagnostic in here
                    retval.which = Records_type.nonsurrogatediagnostic_CID;

                    DefaultDiagFormat_type default_diag = new DefaultDiagFormat_type();
                    retval.o = default_diag;

                    default_diag.diagnosticSetId = reg.oidByName("diag-1");
                    default_diag.condition = BigInteger.valueOf(239);
                    default_diag.addinfo = new addinfo_inline14_type();
                    default_diag.addinfo.which = addinfo_inline14_type.v2addinfo_CID;
                    default_diag.addinfo.o = (Object) (oid.toString());

                    return retval;
                }

                LOGGER.finer("requested_syntax=" + requested_syntax);
                requested_syntax_name = requested_syntax.getName();

                if (requested_syntax_name.equals("usmarc")) {
                    //HACK!  USMARC not yet supported...
                    requested_syntax_name = "sutrs";
                }

                LOGGER.finer("requested_syntax_name=" + requested_syntax_name);
            } else {
                requested_syntax_name = "sutrs"; //REVISIT: should this be

                //default?  We're sure to have it...
                requested_syntax = reg.lookupByName(requested_syntax_name);
            }

            st.setRequestedSyntax(requested_syntax);
            st.setRequestedSyntaxName(requested_syntax_name);

            InformationFragment[] raw_records;
            RecordFormatSpecification rfSpec = new RecordFormatSpecification(requested_syntax_name,
                    null, recordFormatSetname);
            LOGGER.finer("calling getFragment(" + (start) + "," + count + ")");
            raw_records = st.getTaskResultSet().getFragment(start, count, rfSpec);

            if (raw_records == null) {
                throw new PresentException("Error retrieving records", "30");
            }

            for (int i = 0; i < raw_records.length; i++) {
                LOGGER.finer("Adding record " + i + " to result");

                NamePlusRecord_type npr = new NamePlusRecord_type();
                npr.name = raw_records[i].getSourceCollectionName();
                npr.record = new record_inline13_type();
                npr.record.which = record_inline13_type.retrievalrecord_CID;

                EXTERNAL_type rec = new EXTERNAL_type();
                npr.record.o = rec;

                if (requested_syntax_name.equals(Z3950Constants.RECSYN_HTML)
                        || requested_syntax_name.equals("sgml")) {
                    LOGGER.finer("Returning OctetAligned record for "
                        + requested_syntax_name);
                    rec.direct_reference = reg.oidByName(requested_syntax_name);
                    rec.encoding = new encoding_inline0_type();
                    rec.encoding.which = encoding_inline0_type.octet_aligned_CID;

                    String raw_string = (String) raw_records[i]
                        .getOriginalObject();
                    rec.encoding.o = raw_string.getBytes();

                    if (raw_string.length() == 0) {
                        // can't make a html record
                        retval.which = Records_type.nonsurrogatediagnostic_CID;

                        DefaultDiagFormat_type default_diag = new DefaultDiagFormat_type();
                        retval.o = default_diag;

                        default_diag.diagnosticSetId = reg.oidByName("diag-1");
                        default_diag.condition = BigInteger.valueOf(227);
                        default_diag.addinfo = new addinfo_inline14_type();
                        default_diag.addinfo.which = addinfo_inline14_type.v2addinfo_CID;
                        default_diag.addinfo.o = (Object) "1.2.840.10003.5.109.3";

                        return retval;
                    }
                } else if (requested_syntax_name.equals(
                            Z3950Constants.RECSYN_XML)) {
                    // Since XML is our canonical internal schema,
                    //all realisations of InformationFragment
                    // are capable of providing an XML representation of
                    //themselves, so just use the
                    // Fragments getDocument method.
                    LOGGER.finer("Returning OctetAligned XML");

                    java.io.StringWriter sw = new java.io.StringWriter();

                    try {
                        OutputFormat format = new OutputFormat(raw_records[i]
                                .getDocument());
                        XMLSerializer serial = new XMLSerializer(sw, format);
                        serial.asDOMSerializer();
                        serial.serialize(raw_records[i].getDocument()
                                                       .getDocumentElement());
                    } catch (Exception e) {
                        LOGGER.severe("Problem serializing dom tree to"
                            + " result record" + e.getMessage());
                    }

                    rec.direct_reference = reg.oidByName(requested_syntax_name);
                    rec.encoding = new encoding_inline0_type();
                    rec.encoding.which = encoding_inline0_type.octet_aligned_CID;
                    rec.encoding.o = sw.toString().getBytes();
                } else { //if  ( requested_syntax_name.equals

                    //    (Z3950Constants.RECSYN_SUTRS)){
                    rec.direct_reference = reg.oidByName(requested_syntax_name);
                    rec.encoding = new encoding_inline0_type();
                    rec.encoding.which = encoding_inline0_type.single_asn1_type_CID;
                    rec.encoding.o = ((String) (raw_records[i]
                        .getOriginalObject()));
                }

                v.add(npr);
            }
        } catch (PresentException pe) {
            LOGGER.warning("Processing present exception: " + pe.toString());

            // Need to set up diagnostic in here
            retval.which = Records_type.nonsurrogatediagnostic_CID;

            DefaultDiagFormat_type default_diag = new DefaultDiagFormat_type();
            retval.o = default_diag;

            default_diag.diagnosticSetId = reg.oidByName("diag-1");

            if (pe.additional != null) {
                default_diag.condition = BigInteger.valueOf(Long.parseLong(
                            pe.additional.toString()));
            } else {
                default_diag.condition = BigInteger.valueOf(0);
            }

            default_diag.addinfo = new addinfo_inline14_type();
            default_diag.addinfo.which = addinfo_inline14_type.v2addinfo_CID;
            default_diag.addinfo.o = (Object) (pe.toString());
        }

        LOGGER.finer("retval = " + retval);

        return retval;
    }

    //TODO: It'd be nice to have better diagnostics, use explicit diagnostic
    //(use DiagFormat_type from jzkit) and specify exactly what the problem is
    private Records_type createNSD(String diag_code, String additional) {
        Records_type retval = new Records_type();
        retval.which = Records_type.nonsurrogatediagnostic_CID;

        DefaultDiagFormat_type default_diag = new DefaultDiagFormat_type();
        retval.o = default_diag;

        default_diag.diagnosticSetId = reg.oidByName("diag-1");

        if (diag_code != null) {
            default_diag.condition = BigInteger.valueOf(Long.parseLong(
                        diag_code));
        } else {
            default_diag.condition = BigInteger.valueOf(0);
        }

        default_diag.addinfo = new addinfo_inline14_type();
        default_diag.addinfo.which = addinfo_inline14_type.v2addinfo_CID;
        default_diag.addinfo.o = (Object) (additional);

        return retval;
    }

    /**
     * not supported, needed for TargetADPU interface
     */
    public void incomingAccessControlRequest(APDUEvent e) {
        LOGGER.finer("Incoming accessControlRequest");
    }

    /**
     * not supported, needed for TargetADPU interface
     */
    public void incomingAccessControlResponse(APDUEvent e) {
        LOGGER.finer("Incoming AccessControlResponse");
    }

    /**
     * not supported, needed for TargetADPU interface
     */
    public void incomingResourceControlRequest(APDUEvent e) {
        LOGGER.finer("Incoming resourceControlRequest");
    }

    /**
     * not supported, needed for TargetADPU interface
     */
    public void incomingTriggerResourceControlRequest(APDUEvent e) {
        LOGGER.finer("Incoming triggetResourceControlRequest");
    }

    /**
     * not supported, needed for TargetADPU interface
     */
    public void incomingResourceReportRequest(APDUEvent e) {
        LOGGER.finer("Incoming resourceReportRequest");
    }

    public void incomingScanRequest(APDUEvent e) {
        ScanRequest_type scan_request = (ScanRequest_type) (e.getPDU().o);
        int scan_status = 0;

        try {
            if (this.search_service instanceof Scanable) {
                Scanable s = (Scanable) this.search_service;

                if (s.isScanSupported()) {
                    String name = null;
                    OIDRegisterEntry ent = reg.lookupByOID(scan_request.attributeSet);

                    if (ent != null) {
                        name = ent.getName();
                    }

                    RootNode rn = new RootNode();

                    int i1 = ((scan_request.stepSize == null) ? 0
                                                              : scan_request.stepSize
                        .intValue());
                    int i2 = ((scan_request.numberOfTermsRequested == null) ? 0
                                                                            : scan_request.numberOfTermsRequested
                        .intValue());
                    int i3 = ((scan_request.preferredPositionInResponse == null)
                        ? 0 : scan_request.preferredPositionInResponse.intValue());

                    ScanRequestInfo sri = new ScanRequestInfo();
                    sri.collections = scan_request.databaseNames;
                    sri.attribute_set = name;
                    sri.term_list_and_start_point = com.k_int.z3950.util.RPN2Internal
                        .convertAPT(scan_request.termListAndStartPoint, rn);
                    sri.step_size = i1;
                    sri.number_of_terms_requested = i2;
                    sri.position_in_response = i3;

                    ScanInformation scan_result = null;

                    try {
                        scan_result = s.doScan(sri);

                        assoc.sendScanResponse(scan_request.referenceId,
                            BigInteger.valueOf(i1),
                            BigInteger.valueOf(scan_status),
                            BigInteger.valueOf(scan_result.position),
                            scan_result.results, scan_request.attributeSet, null);
                    }
                     catch (ScanException scan_e) {
                        // TODO this is a short term fix to the new requirement to throw a scan exception
                        assoc.sendScanResponse(scan_request.referenceId,
                            BigInteger.valueOf(i1), BigInteger.valueOf(3),
                            BigInteger.valueOf(0), null,
                            scan_request.attributeSet, scan_e);
                    }
                }
            }
        } catch (java.io.IOException ioe) {
            ioe.printStackTrace();
        }
    }

    /*  public void incomingScanRequest(APDUEvent e)
       {
         ScanRequest_type scan_request = (ScanRequest_type) (e.getPDU().o);
         int step_size = 0;
         int scan_status = 0;
         int number_of_entries_returned = 0;
         int position_of_term = 0;
         try
         {
           if ( this.search_service instanceof Scanable )
           {
             Scanable s = (Scanable)this.search_service;
             if ( s.isScanSupported() )
             {
               String name = null;
               OIDRegisterEntry ent = reg.lookupByOID(scan_request.attributeSet);
               if ( ent != null )
                 name=ent.getName();
               RootNode rn = new RootNode();
               int i1 = ( scan_request.stepSize == null ? 0 : scan_request.stepSize.intValue() );
               int i2 = ( scan_request.numberOfTermsRequested == null ? 0 :
                                 scan_request.numberOfTermsRequested.intValue() );
               int i3 = ( scan_request.preferredPositionInResponse == null ? 0 :
                                 scan_request.preferredPositionInResponse.intValue() );
               ScanRequestInfo sri = new ScanRequestInfo();
               sri.collections = scan_request.databaseNames;
               sri.attribute_set = name;
               sri.term_list_and_start_point = com.k_int.z3950.util.RPN2Internal.convertAPT(scan_request.termListAndStartPoint,rn);
               sri.step_size = i1;
               sri.number_of_terms_requested = i2;
               sri.position_in_response = i3;
               ScanInformation scan_result = s.doScan(sri);
               assoc.sendScanResponse(scan_request.referenceId,
                                      BigInteger.valueOf(i1),
                                      BigInteger.valueOf(scan_status),
                                      BigInteger.valueOf(scan_result.position),
                                      scan_result.results,
                                      scan_request.attributeSet,
                                      null);
             }
           }
         }
         catch ( java.io.IOException ioe )
         {
           ioe.printStackTrace();
         }
         }*/

    /**
     * not supported, needed for TargetADPU interface
     */
    public void incomingSortRequest(APDUEvent e) {
        LOGGER.finer("Incoming sortRequest");
    }

    /**
     * not supported, needed for TargetADPU interface
     */
    public void incomingSegmentRequest(APDUEvent e) {
        LOGGER.finer("Incoming segmentRequest");
    }

    /**
     * not supported, needed for TargetADPU interface
     */
    public void incomingExtendedServicesRequest(APDUEvent e) {
        LOGGER.finer("Incoming extendedServicesRequest");
    }
}
TOP

Related Classes of org.vfny.geoserver.zserver.GeoZServerAssociation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.