/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You 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 com.esri.gpt.catalog.publication;
import com.esri.gpt.catalog.arcgis.metadata.AGSProcessor;
import com.esri.gpt.catalog.arcgis.metadata.AGSProcessorConfig;
import com.esri.gpt.framework.collection.StringAttributeMap;
import com.esri.gpt.framework.http.CredentialProvider;
import com.esri.gpt.framework.http.HttpClientRequest;
import com.esri.gpt.framework.security.credentials.UsernamePasswordCredentials;
import com.esri.gpt.framework.util.Val;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
/**
* A factory for instantiating suitable resource processors.
*/
public class ProcessorFactory {
/** constructors ============================================================ */
/** Default constructor. */
public ProcessorFactory() {}
/**
* Interrogates a resource URL to determine an appropriate resource processor.
* @param context the resource processing context
* @param resourceUrl the resource URL to be interrogated
* @return a processor capable of handling the endpoint (can be null)
* @throws IOException if a communication exception occurs
*/
public ResourceProcessor interrogate(ProcessingContext context, String resourceUrl)
throws IOException {
return interrogate(context, resourceUrl, null);
}
/**
* Interrogates a resource URL to determine an appropriate resource processor.
* @param context the resource processing context
* @param resourceUrl the resource URL to be interrogated
* @param credentials credentials
* @return a processor capable of handling the endpoint (can be null)
* @throws IOException if a communication exception occurs
*/
public ResourceProcessor interrogate(ProcessingContext context, String resourceUrl, UsernamePasswordCredentials credentials)
throws IOException {
// it's xml or ags json or ags soap
// determine the base URL (sans query string)
resourceUrl = Val.chkStr(resourceUrl);
String baseUrl = resourceUrl;
if (baseUrl.indexOf("?") != -1) {
baseUrl = baseUrl.substring(0,baseUrl.indexOf("?"));
}
if (baseUrl.endsWith("/")) {
baseUrl = baseUrl.substring(0,baseUrl.length() - 1);
}
// determine the protocol
boolean isHttpProtocol = false;
boolean isFtpProtocol = false;
boolean isFileProtocol = false;
boolean isFile = false;
boolean isDirectory = false;
boolean wasMalformed = false;
URL url = null;
File file = null;
try {
url = new URL(resourceUrl);
String protocol = Val.chkStr(url.getProtocol()).toLowerCase();
isHttpProtocol = protocol.equals("http") || protocol.equals("https");
isFtpProtocol = protocol.equals("ftp") || protocol.equals("ftps");
isFileProtocol = protocol.equals("file");
} catch (MalformedURLException e) {
wasMalformed = true;
}
// check to see if this is a reference to a server side file or directory
// TODO: should we allow this??
if (isFileProtocol || wasMalformed) {
String filePath = resourceUrl;
if (isFileProtocol) {
filePath = url.getPath();
}
try {
file = new File(filePath);
if (file.exists()) {
isFile = file.isFile();
isDirectory = file.isDirectory();
}
} catch (SecurityException se) {
// read only
}
}
if (isDirectory) {
// no applicable processor
} else if (isFile) {
SingleXmlProcessor xp = new SingleXmlProcessor(context,file);
return xp;
} else if (isFtpProtocol) {
// no applicable processor
} else if (isHttpProtocol) {
return this.interrogateHttpEndpoint(context,url,credentials);
} else {
// no applicable processor
}
return null;
}
/**
* Interrogates an HTTP endpoint.
* @param context the resource processing context
* @param url the URL to be interrogated
* @param credentials credentials
* @return a processor capable of handling the endpoint (can be null)
* @throws IOException if a communication exception occurs
*/
private ResourceProcessor interrogateHttpEndpoint(ProcessingContext context, URL url, UsernamePasswordCredentials credentials)
throws IOException {
// read the character response from the endpoint
String fullUrl = url.toExternalForm();
HttpClientRequest httpClient = context.getHttpClient();
httpClient.setUrl(fullUrl);
httpClient.setCredentialProvider(
credentials==null || credentials.getUsername().length()==0 || credentials.getPassword().length()==0?
null:
new CredentialProvider(credentials.getUsername(),credentials.getPassword())
);
String response = Val.chkStr(httpClient.readResponseAsCharacters());
if (response.length() > 0) {
// first try ArcGIS Server
boolean interrofgateAGS = true;
StringAttributeMap params = context.getRequestContext().getCatalogConfiguration().getParameters();
if (Val.chkStr(params.getValue("AGSProcessor.interrogation.enabled")).equalsIgnoreCase("false")) {
interrofgateAGS = false;
} else if (!AGSProcessorConfig.isAvailable()) {
interrofgateAGS = false;
}
if (interrofgateAGS) {
AGSProcessor ags = new AGSProcessor(context);
ags.setCredentials(credentials);
try {
if (ags.interrogate(url,response)) {
return ags;
}
} catch (IOException ioe) {
if (ags.getTarget().getWasRecognized()) {
throw ioe;
}
}
}
}
// default to s single xml processor
SingleXmlProcessor xp = new SingleXmlProcessor(context,url.toExternalForm(),response);
return xp;
}
}