/** * Copyright (C) 2012 52°North Initiative for Geospatial Open Source Software GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.n52.sos; import java.io.IOException; import org.n52.sos.db.impl.AccessGdbForAnalysisImpl; import org.n52.util.ExceptionSupporter; import org.n52.util.logging.Logger; import com.esri.arcgis.carto.IMapServerDataAccess; import com.esri.arcgis.interop.AutomationException; import com.esri.arcgis.interop.extn.ArcGISExtension; import com.esri.arcgis.interop.extn.ServerObjectExtProperties; import com.esri.arcgis.server.IServerObjectExtension; import com.esri.arcgis.server.IServerObjectHelper; import com.esri.arcgis.server.json.JSONArray; import com.esri.arcgis.server.json.JSONObject; import com.esri.arcgis.system.IObjectConstruct; import com.esri.arcgis.system.IPropertySet; import com.esri.arcgis.system.IRESTRequestHandler; import com.esri.arcgis.system.ServerUtilities; /** * The main class of this ArcGIS Server Object Extension (SOE). * * @author <a href="mailto:broering@52north.org">Arne Broering</a> */ @ArcGISExtension @ServerObjectExtProperties( displayName = "Database_analyzer_for_the_SOS_extension", description = "Database_analyzer_for_the_SOS_extension") public class DBInspector implements IServerObjectExtension, IObjectConstruct, IRESTRequestHandler { private static final long serialVersionUID = 1L; public Logger LOGGER = Logger.getLogger(DBInspector.class.getName()); private String tableName; private String tablePkField; protected AccessGdbForAnalysisImpl geoDB; private IMapServerDataAccess mapServerDataAccess; /** * constructs a new server object extension * * @throws Exception */ public DBInspector() throws Exception { super(); } /************************************************************************************* * IServerObjectExtension methods: *************************************************************************************/ /** * init() is called once, when the instance of the SOE is created. */ public void init(IServerObjectHelper soh) throws IOException, AutomationException { Logger.init(ServerUtilities.getServerLogger()); LOGGER.info("Start initializing " + this.getClass().getName() + " SOE."); this.mapServerDataAccess = (IMapServerDataAccess) soh.getServerObject(); LOGGER.info(this.getClass().getName() + " initialized."); } /** * shutdown() is called once when the Server Object's context is being shut * down and is about to go away. */ public void shutdown() throws IOException, AutomationException { /* * The SOE should release its reference on the Server Object Helper. */ LOGGER.info("Shutting down " + this.getClass().getName() + " SOE."); this.mapServerDataAccess = null; this.geoDB = null; // TODO: make sure all references are being cut. } /************************************************************************************* * IConstructObject methods: *************************************************************************************/ /** * construct() is called only once, when the SOE is created, after * IServerObjectExtension.init() is called. This method hands back the * configuration properties for the SOE as a property set. You should * include any expensive initialization logic for your SOE within your * implementation of construct(). */ public void construct(IPropertySet propertySet) throws IOException { LOGGER.debug("construct() is called..."); // TODO --> read in maxNumOfResults from Manager try { LOGGER.debug("Reading properties..."); this.tableName = (String) propertySet.getProperty("tableToAnalyze"); this.tablePkField = (String) propertySet.getProperty("tablePkField"); } catch (Exception e) { LOGGER.severe("There was a problem while reading properties", e); throw new IOException(e); } try { // create database access this.geoDB = new AccessGdbForAnalysisImpl(this); } catch (Exception e) { LOGGER.severe("There was a problem while creating DB access: \n" + e.getLocalizedMessage() + "\n" + ExceptionSupporter.createStringFromStackTrace(e)); throw new IOException(e); } } /************************************************************************************* * IRESTRequestHandler methods: *************************************************************************************/ /** * This method returns the resource hierarchy of a REST based SOE in JSON * format. */ @Override public String getSchema() throws IOException, AutomationException { LOGGER.verbose("getSchema() is called..."); JSONObject arcGisSos = ServerUtilities.createResource("DB_Analyzer_for_ArcGIS_SOS_Extension", "A_DBAnalyzer_for_the_SOS_extension_for_ArcGIS_Server", false, false); JSONArray operationArray = new JSONArray(); JSONObject tableNamesObject = ServerUtilities.createResource("ReadTableNamesFromDB", "reads all table names from DB", false, false); JSONObject analyzeProcedureTableObject = ServerUtilities.createResource("AnalyzeTableUsingProperties", "analyzes a specified table", false, false); // operationArray.put(ServerUtilities.createOperation("ReadTableNamesFromDB", "db", "json", false)); operationArray.put(ServerUtilities.createOperation("AnalyzeTable", "tableName", "json", false)); // operationArray.put(ServerUtilities.createOperation("AnalyzeProcedureTable", "bla", "json", false)); JSONArray resourceArray = new JSONArray(); resourceArray.put(tableNamesObject); resourceArray.put(analyzeProcedureTableObject); arcGisSos.put("resources", resourceArray); // arcGisSos.put("operations", operationArray); return arcGisSos.toString(); } /** * This method handles REST requests by determining whether an operation or * resource has been invoked and then forwards the request to appropriate * methods. * * @param capabilities * The capabilities supported by the SOE. An admin can choose * which capabilities are enabled on a particular SOE (in ArcGIS * Manager or ArcCatalog), based on certain criteria such as * security roles. This list of allowed capabilities is then sent * to this method, at runtime, as a comma separated list. * @param resourceName * Name of the resource being addressed relative to the root SOE * resource. If empty, its assumed that root resource is being * addressed. E.g.: "procedures/mysensor123". For resource * requests, the operationName parameter of this method will be * an empty string (""). * @param operationName * Name of the operation being invoked. If empty, description of * resource is returned. * @param operationInput * Input parameters to the operation specified by operationName * parameter, encoded as a JSON formatted string. The REST * handler coerces the input parameters of an operation into a * JSON string. The request parameter names become the JSON * property names. The values are attempted to be coerced to * valid JSON types - numbers, booleans, JSON objects, JSON * arrays. If they cannot be coerced to any of the types * mentioned above, they'll be treated as strings. * @param outputFormat * OutputFormat of operation. The value of the format parameter f * of the REST API. */ @Override public byte[] handleRESTRequest(String capabilities, String resourceName, String operationName, String operationInput, String outputFormat, String requestProperties, String[] responseProperties) throws IOException, AutomationException { LOGGER.info("Starting to handle REST request..."); try { // resource if (operationName.length() == 0) { if (resourceName == null || resourceName.matches("")) { JSONObject json = new JSONObject(); json.append("Welcome to the DB Analyzer.", "Please use the links below to analyze the DB underlying this SOE."); return json.toString().getBytes("utf-8"); } else if (resourceName.matches("ReadTableNamesFromDB")) { return geoDB.readTableNamesFromDB().toString().getBytes("utf-8"); } else if (resourceName.matches("AnalyzeTableUsingProperties")) { return geoDB.analyzeProcedureTable().toString().getBytes("utf-8"); } else { throw new Exception("Resource '" + resourceName + "' not supported."); } } else { // extract operation input parameters to Map: JSONObject inputObject = new JSONObject(operationInput); // if (operationName.equalsIgnoreCase("ReadTableNamesFromDB")) { // return geoDB.readTableNamesFromDB().toString().getBytes("utf-8"); // } if (operationName.equalsIgnoreCase("AnalyzeTable")) { return geoDB.analyzeTable(inputObject).toString().getBytes("utf-8"); } // else if (operationName.equalsIgnoreCase("AnalyzeProcedureTable")) { // return geoDB.analyzeProcedureTable().toString().getBytes("utf-8"); // } else { throw new Exception("Operation '" + operationName + "' on resource '" + resourceName + "' not supported."); } } } catch (Exception e) { LOGGER.severe("Error while handle REST request", e); // send out error: return ServerUtilities.sendError(3, "An exception occurred: " + e.toString(), ExceptionSupporter.createStringArrayFromStackTrace(e.getStackTrace())).getBytes("utf-8"); } } public IMapServerDataAccess getMapServerDataAccess() { return this.mapServerDataAccess; } public String getTable() { return tableName; } public String getTablePkField() { return tablePkField; } }