/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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 org.apache.airavata.workflow.model.component.web;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTML.Tag;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;
import org.apache.airavata.common.utils.IOUtil;
import org.apache.airavata.workflow.model.component.ComponentException;
import org.apache.airavata.workflow.model.component.ComponentReference;
import org.apache.airavata.workflow.model.component.ComponentRegistry;
import org.apache.airavata.workflow.model.component.ComponentRegistryException;
import org.apache.airavata.workflow.model.component.ws.WSComponent;
import org.apache.airavata.workflow.model.component.ws.WSComponentFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WebComponentRegistry extends ComponentRegistry {
private static final Logger logger = LoggerFactory.getLogger(WebComponentRegistry.class);
private URL url;
private List<ComponentReference> tree;
private Map<String, List<WSComponent>> componentsMap;
/**
* Creates a WebComponentRegistryClient
*
* @param urlString
* @throws MalformedURLException
* @throws IOException
*/
public WebComponentRegistry(String urlString) throws MalformedURLException, IOException {
this(new URL(urlString));
}
/**
* Creates a WebComponentRegistryClient
*
* @param url
* The URL of the web page.
*/
public WebComponentRegistry(URL url) {
this.url = url;
this.componentsMap = new HashMap<String, List<WSComponent>>();
}
/**
* @see org.apache.airavata.workflow.model.component.registry.ComponentRegistry#getName()
*/
@Override
public String getName() {
return this.url.toString();
}
/**
* @see org.apache.airavata.workflow.model.component.registry.ComponentRegistry#getComponentReferenceList()
*/
@Override
public List<ComponentReference> getComponentReferenceList() throws ComponentRegistryException {
tree = new ArrayList<ComponentReference>();
parse();
return this.tree;
}
/**
* Returns a list of component of a specified name.
*
* @param name
* The name of the component. The name here is a relative URL specified in <a href="name"> tag, and is
* same as the name of a corresponding ComponentTree.
* @return The list of components of the specified name
*/
public List<WSComponent> getComponents(String name) {
// This method is only used from a test.
List<WSComponent> components = this.componentsMap.get(name);
return components;
}
private void parse() throws ComponentRegistryException {
try {
HttpURLConnection connection = (HttpURLConnection) this.url.openConnection();
connection.setInstanceFollowRedirects(false);
connection.connect();
int count = 0;
// TODO checking 3 is not enough
while (String.valueOf(connection.getResponseCode()).startsWith("3")) {
String location = connection.getHeaderField("Location");
logger.debug("Redirecting to " + location);
connection.disconnect();
this.url = new URL(location);
connection = (HttpURLConnection) this.url.openConnection();
connection.setInstanceFollowRedirects(false);
connection.connect();
count++;
if (count > 10) {
throw new ComponentRegistryException("Too many redirect");
}
}
InputStream inputStream = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream);
HtmlRegistryParserCallback callback = new HtmlRegistryParserCallback();
ParserDelegator parser = new ParserDelegator();
parser.parse(reader, callback, false);
} catch (IOException e) {
throw new ComponentRegistryException(e);
}
}
private void addComponents(String name) {
try {
URL wsdlUrl = new URL(this.url, name);
logger.debug("WSDL URL: " + wsdlUrl);
String wsdlString = IOUtil.readToString(wsdlUrl.openStream());
logger.debug("WSDL: " + wsdlString);
List<WSComponent> components = WSComponentFactory.createComponents(wsdlString);
addComponents(name, components);
} catch (MalformedURLException e) {
// Ignore
logger.error(e.getMessage(), e);
} catch (IOException e) {
// Ignore
logger.error(e.getMessage(), e);
} catch (ComponentException e) {
// Malformed WSDL.
logger.error(e.getMessage(), e);
} catch (RuntimeException e) {
logger.error(e.getMessage(), e);
}
}
private void addComponents(String name, List<WSComponent> components) {
this.componentsMap.put(name, components);
WebComponentReference componentReference = new WebComponentReference(name, components);
this.tree.add(componentReference);
}
private class HtmlRegistryParserCallback extends HTMLEditorKit.ParserCallback {
/**
* @see javax.swing.text.html.HTMLEditorKit.ParserCallback#handleStartTag(javax.swing.text.html.HTML.Tag,
* javax.swing.text.MutableAttributeSet, int)
*/
@Override
public void handleStartTag(Tag tag, MutableAttributeSet attrSet, int pos) {
if (tag == HTML.Tag.A) {
String name = (String) attrSet.getAttribute(HTML.Attribute.HREF);
addComponents(name);
}
}
}
}