/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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.
*/
/**
* @author Z.Paulovics
*/
package org.jboss.arquillian.container.glassfish.clientutils;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.CsrfProtectionFilter;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.api.container.ContainerException;
import com.sun.jersey.multipart.FormDataMultiPart;
import org.jboss.arquillian.container.glassfish.CommonGlassFishConfiguration;
import javax.ws.rs.core.MediaType;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GlassFishClientUtil {
/**
* Status for a successful GlassFish exit code deployment.
*/
public static final String SUCCESS = "SUCCESS";
/**
* Status for a GlassFish exit code deployment which ended in warning.
*/
public static final String WARNING = "WARNING";
private CommonGlassFishConfiguration configuration;
private String adminBaseUrl;
private static final Logger log = Logger.getLogger(GlassFishClientUtil.class.getName());
public GlassFishClientUtil(CommonGlassFishConfiguration configuration, String adminBaseUrl) {
this.configuration = configuration;
this.adminBaseUrl = adminBaseUrl;
}
public CommonGlassFishConfiguration getConfiguration() {
return configuration;
}
public Map<String, String> getAttributes(String additionalResourceUrl) {
Map responseMap = GETRequest(additionalResourceUrl);
Map<String, String> attributes = new HashMap<String, String>();
Map resultExtraProperties = (Map) responseMap.get("extraProperties");
if (resultExtraProperties != null) {
attributes = (Map<String, String>) resultExtraProperties.get("entity");
}
return attributes;
}
public Map<String, String> getChildResources(String additionalResourceUrl) throws ContainerException {
Map responseMap = GETRequest(additionalResourceUrl);
Map<String, String> childResources = new HashMap<String, String>();
Map resultExtraProperties = (Map) responseMap.get("extraProperties");
if (resultExtraProperties != null) {
childResources = (Map<String, String>) resultExtraProperties.get("childResources");
}
return childResources;
}
public Map GETRequest(String additionalResourceUrl) {
ClientResponse response = prepareClient(additionalResourceUrl).get(ClientResponse.class);
Map responseMap = getResponseMap(response);
return responseMap;
}
public List<Map> getInstancesList(String additionalResourceUrl) throws ContainerException {
Map responseMap = GETRequest(additionalResourceUrl);
List<Map> instancesList = new ArrayList();
Map resultExtraProperties = (Map) responseMap.get("extraProperties");
if (resultExtraProperties != null) {
instancesList = (List<Map>) resultExtraProperties.get("instanceList");
}
return instancesList;
}
public Map POSTMultiPartRequest(String additionalResourceUrl, FormDataMultiPart form) {
ClientResponse response = prepareClient(additionalResourceUrl).type(MediaType.MULTIPART_FORM_DATA_TYPE)
.post(ClientResponse.class, form);
Map responseMap = getResponseMap(response);
return responseMap;
}
/**
* Basic REST call preparation, with the additional resource url appended
*
* @param additionalResourceUrl
* url portion past the base to use
*
* @return the resource builder to execute
*/
private WebResource.Builder prepareClient(String additionalResourceUrl) {
final Client client = Client.create();
if (configuration.isAuthorisation()) {
client.addFilter(new HTTPBasicAuthFilter(
configuration.getAdminUser(),
configuration.getAdminPassword()));
}
client.addFilter(new CsrfProtectionFilter());
return client.resource(this.adminBaseUrl + additionalResourceUrl)
.accept(MediaType.APPLICATION_XML_TYPE)
.header("X-GlassFish-3", "ignore");
}
private Map getResponseMap(ClientResponse response) throws ContainerException {
Map responseMap = new HashMap();
String message = "";
final String xmlDoc = response.getEntity(String.class);
// Marshalling the XML format response to a java Map
if (xmlDoc != null && !xmlDoc.isEmpty()) {
responseMap = xmlToMap(xmlDoc);
message = "exit_code: " + responseMap.get("exit_code")
+ ", message: " + responseMap.get("message");
}
ClientResponse.Status status = ClientResponse.Status.fromStatusCode(response.getStatus());
if (status.getFamily() == javax.ws.rs.core.Response.Status.Family.SUCCESSFUL) {
// O.K. the jersey call was successful, what about the GlassFish server response?
if (responseMap.get("exit_code") == null) {
throw new GlassFishClientException(message);
} else if (WARNING.equals(responseMap.get("exit_code"))) {
// Warning is not a failure - some warnings in GlassFish are inevitable (i.e. persistence-related: ARQ-606)
log.warning("Deployment resulted in a warning: " + message);
} else if (!SUCCESS.equals(responseMap.get("exit_code"))) {
// Response is not a warning nor success - it's surely a failure.
throw new GlassFishClientException(message);
}
} else if (status.getReasonPhrase() == "Not Found") {
// the REST resource can not be found (for optional resources it can be O.K.)
message += " [status: " + status.getFamily() + " reason: " + status.getReasonPhrase() + "]";
log.warning(message);
} else {
message += " [status: " + status.getFamily() + " reason: " + status.getReasonPhrase() + "]";
log.severe(message);
throw new ContainerException(message);
}
return responseMap;
}
/**
* Marshalling a Glassfish Mng API response XML document to a java Map object
*
* @param XML
* document
*
* @return map containing the XML doc representation in java map format
*/
public Map xmlToMap(String document) {
if (document == null) {
return new HashMap();
}
InputStream input = null;
Map map = null;
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.IS_VALIDATING, false);
input = new ByteArrayInputStream(document.trim().getBytes("UTF-8"));
XMLStreamReader stream = factory.createXMLStreamReader(input);
while (stream.hasNext()) {
int currentEvent = stream.next();
if (currentEvent == XMLStreamConstants.START_ELEMENT) {
if ("map".equals(stream.getLocalName())) {
map = resolveXmlMap(stream);
}
}
}
} catch (Exception ex) {
log.log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
} finally {
try {
input.close();
} catch (IOException ex) {
log.log(Level.SEVERE, null, ex);
}
}
return map;
}
private Map resolveXmlMap(XMLStreamReader stream) throws XMLStreamException {
boolean endMapFlag = false;
Map<String, Object> entry = new HashMap<String, Object>();
String key = null;
String elementName = null;
while (!endMapFlag) {
int currentEvent = stream.next();
if (currentEvent == XMLStreamConstants.START_ELEMENT) {
if ("entry".equals(stream.getLocalName())) {
key = stream.getAttributeValue(null, "key");
String value = stream.getAttributeValue(null, "value");
if (value != null) {
entry.put(key, value);
key = null;
}
} else if ("map".equals(stream.getLocalName())) {
Map value = resolveXmlMap(stream);
entry.put(key, value);
} else if ("list".equals(stream.getLocalName())) {
List value = resolveXmlList(stream);
entry.put(key, value);
} else {
elementName = stream.getLocalName();
}
} else if (currentEvent == XMLStreamConstants.END_ELEMENT) {
if ("map".equals(stream.getLocalName())) {
endMapFlag = true;
}
elementName = null;
} else {
String document = stream.getText();
if (elementName != null) {
if ("number".equals(elementName)) {
if (document.contains(".")) {
entry.put(key, Double.parseDouble(document));
} else {
entry.put(key, Long.parseLong(document));
}
} else if ("string".equals(elementName)) {
entry.put(key, document);
}
elementName = null;
}
} // end if
} // end while
return entry;
}
private List resolveXmlList(XMLStreamReader stream) throws XMLStreamException {
boolean endListFlag = false;
List list = new ArrayList();
String elementName = null;
while (!endListFlag) {
int currentEvent = stream.next();
if (currentEvent == XMLStreamConstants.START_ELEMENT) {
if ("map".equals(stream.getLocalName())) {
list.add(resolveXmlMap(stream));
} else {
elementName = stream.getLocalName();
}
} else if (currentEvent == XMLStreamConstants.END_ELEMENT) {
if ("list".equals(stream.getLocalName())) {
endListFlag = true;
}
elementName = null;
} else {
String document = stream.getText();
if (elementName != null) {
if ("number".equals(elementName)) {
if (document.contains(".")) {
list.add(Double.parseDouble(document));
} else {
list.add(Long.parseLong(document));
}
} else if ("string".equals(elementName)) {
list.add(document);
}
elementName = null;
}
} // end if
} // end while
return list;
}
}