Issue 230: corrected URI parsing so that we can access ibm image manifests

This commit is contained in:
Adrian Cole 2010-06-09 22:46:25 -07:00
parent ab5e8b3ab4
commit 50b1aa3cae
7 changed files with 114 additions and 37 deletions

View File

@ -250,10 +250,16 @@ public class HttpUtils {
/**
* Used to extract the URI and authentication data from a String. Note that the java URI class
* breaks, if there are special characters like '/' present. Otherwise, we wouldn't need this
* class, and we could simply use URI.create("uri").getUserData();
* class, and we could simply use URI.create("uri").getUserData(); Also, URI breaks if there
* are curly braces.
*
*/
public static URI createUri(String uriPath) {
List<String> onQuery = Lists.newArrayList(Splitter.on('?').split(uriPath));
if (onQuery.size() == 2){
onQuery.add(urlEncode(onQuery.remove(1), '=','&'));
uriPath = Joiner.on('?').join(onQuery);
}
if (uriPath.indexOf('@') != 1) {
List<String> parts = Lists.newArrayList(Splitter.on('@').split(uriPath));
String path = parts.remove(parts.size() - 1);

View File

@ -45,6 +45,12 @@ public class HttpUtilsTest extends PerformanceTest {
assertEquals(HttpUtils.urlEncode("/read-tests/ tep", '/'), "/read-tests/%20tep");
}
public void testIBM() {
URI ibm = HttpUtils
.createUri("https://www-180.ibm.com/cloud/enterprise/beta/ram/assetDetail/generalDetails.faces?guid={A31FF849-0E97-431A-0324-097385A46298}&v=1.2");
assertEquals(ibm.getQuery(), "guid={A31FF849-0E97-431A-0324-097385A46298}&v=1.2");
}
public void testAtmos() {
URI creds = HttpUtils
.createUri("compute://domain/user:Base64==@azureblob/container-hyphen/prefix");

View File

@ -0,0 +1,70 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.jclouds.ibmdev.config;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.Map;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.config.ParserModule.DateAdapter;
import org.jclouds.http.functions.config.ParserModule.LongDateAdapter;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
*
*
* @author Adrian Cole
*/
public class IBMDeveloperCloudParserModule extends AbstractModule {
@Singleton
public static class CurlyBraceCapableURIAdapter implements JsonDeserializer<URI> {
@Override
public URI deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context)
throws JsonParseException {
String toParse = jsonElement.getAsJsonPrimitive().getAsString();
URI toReturn = HttpUtils.createUri(toParse);
return toReturn;
}
}
@SuppressWarnings("unchecked")
@Provides
@Singleton
@Named(Constants.PROPERTY_GSON_ADAPTERS)
public Map<Class, Object> provideCustomAdapterBindings(CurlyBraceCapableURIAdapter adapter) {
return ImmutableMap.<Class, Object> of(URI.class, adapter);
}
@Override
protected void configure() {
bind(DateAdapter.class).to(LongDateAdapter.class);
}
}

View File

@ -32,8 +32,6 @@ import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.functions.config.ParserModule.DateAdapter;
import org.jclouds.http.functions.config.ParserModule.LongDateAdapter;
import org.jclouds.ibmdev.IBMDeveloperCloud;
import org.jclouds.ibmdev.IBMDeveloperCloudAsyncClient;
import org.jclouds.ibmdev.IBMDeveloperCloudClient;
@ -63,6 +61,7 @@ public class IBMDeveloperCloudRestClientModule extends
super(IBMDeveloperCloudClient.class, IBMDeveloperCloudAsyncClient.class);
}
@Provides
@Singleton
public BasicAuthentication provideBasicAuthentication(
@ -92,7 +91,7 @@ public class IBMDeveloperCloudRestClientModule extends
@Override
protected void configure() {
bind(DateAdapter.class).to(LongDateAdapter.class);
install(new IBMDeveloperCloudParserModule());
super.configure();
}

View File

@ -18,6 +18,7 @@
*/
package org.jclouds.ibmdev.domain;
import java.net.URI;
import java.util.Date;
import java.util.Set;
@ -61,10 +62,8 @@ public class Image {
}
private String name;
/**
* Note that this isn't a URI, as parsing fails due to IBM including '{' characters in the path.
*/
private String manifest;
private URI manifest;
private int state;
private Visibility visibility;
private String owner;
@ -74,10 +73,7 @@ public class Image {
private String location;
private Set<String> supportedInstanceTypes = Sets.newLinkedHashSet();
private Set<String> productCodes = Sets.newLinkedHashSet();
/**
* Note that this isn't a URI, as parsing fails due to IBM including '{' characters in the path.
*/
private String documentation;
private URI documentation;
private String id;
private String description;
@ -89,11 +85,11 @@ public class Image {
this.name = name;
}
public String getManifest() {
public URI getManifest() {
return manifest;
}
public void setManifest(String manifest) {
public void setManifest(URI manifest) {
this.manifest = manifest;
}
@ -169,11 +165,11 @@ public class Image {
this.productCodes = productCodes;
}
public String getDocumentation() {
public URI getDocumentation() {
return documentation;
}
public void setDocumentation(String documentation) {
public void setDocumentation(URI documentation) {
this.documentation = documentation;
}

View File

@ -25,7 +25,9 @@ import java.io.IOException;
import java.util.Date;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.ibmdev.config.IBMDeveloperCloudParserModule;
import org.jclouds.ibmdev.domain.Image;
import org.jclouds.ibmdev.domain.Image.Visibility;
import org.testng.annotations.BeforeTest;
@ -47,13 +49,8 @@ public class ParseImageFromJsonTest {
@BeforeTest
protected void setUpInjector() throws IOException {
Injector injector = Guice.createInjector(new ParserModule() {
@Override
protected void configure() {
bind(DateAdapter.class).to(LongDateAdapter.class);
super.configure();
}
});
Injector injector = Guice.createInjector(new ParserModule(),
new IBMDeveloperCloudParserModule());
handler = injector.getInstance(ParseImageFromJson.class);
}
@ -62,7 +59,8 @@ public class ParseImageFromJsonTest {
Image image = new Image();
image.setName("Rational Requirements Composer");
image
.setManifest("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{28C7B870-2C0A-003F-F886-B89F5B413B77}/1.0/parameters.xml");
.setManifest(HttpUtils
.createUri("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{28C7B870-2C0A-003F-F886-B89F5B413B77}/1.0/parameters.xml"));
image.setState(1);
image.setVisibility(Visibility.PUBLIC);
image.setOwner("mutdosch@us.ibm.com");
@ -73,7 +71,8 @@ public class ParseImageFromJsonTest {
image.setSupportedInstanceTypes(ImmutableSet.of("LARGE", "MEDIUM"));
// image.setProductCodes();
image
.setDocumentation("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{28C7B870-2C0A-003F-F886-B89F5B413B77}/1.0/GettingStarted.html");
.setDocumentation(HttpUtils
.createUri("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{28C7B870-2C0A-003F-F886-B89F5B413B77}/1.0/GettingStarted.html"));
image.setId("10005598");
image
.setDescription("Rational Requirements Composer helps teams define and use requirements effectively across the project lifecycle.");

View File

@ -24,7 +24,9 @@ import java.util.Date;
import java.util.Set;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.ibmdev.config.IBMDeveloperCloudParserModule;
import org.jclouds.ibmdev.domain.Image;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
@ -45,13 +47,8 @@ public class ParseImagesFromJsonTest {
@BeforeTest
protected void setUpInjector() throws IOException {
Injector injector = Guice.createInjector(new ParserModule() {
@Override
protected void configure() {
bind(DateAdapter.class).to(LongDateAdapter.class);
super.configure();
}
});
Injector injector = Guice.createInjector(new ParserModule(),
new IBMDeveloperCloudParserModule());
handler = injector.getInstance(ParseImagesFromJson.class);
}
@ -60,7 +57,8 @@ public class ParseImagesFromJsonTest {
image1.setName("Rational Build Forge Agent");
image1
.setManifest("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{A233F5A0-05A5-F21D-3E92-3793B722DFBD}/1.0/parameters.xml");
.setManifest(HttpUtils
.createUri("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{A233F5A0-05A5-F21D-3E92-3793B722DFBD}/1.0/parameters.xml"));
image1.setState(1);
image1.setVisibility(Image.Visibility.PUBLIC);
image1.setOwner("SYSTEM");
@ -71,7 +69,8 @@ public class ParseImagesFromJsonTest {
image1.setSupportedInstanceTypes(ImmutableSet.of("SMALL", "MEDIUM", "LARGE"));
image1.setProductCodes(ImmutableSet.of("fd2d0478b132490897526b9b4433a334"));
image1
.setDocumentation("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{A233F5A0-05A5-F21D-3E92-3793B722DFBD}/1.0/GettingStarted.html");
.setDocumentation(HttpUtils
.createUri("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{A233F5A0-05A5-F21D-3E92-3793B722DFBD}/1.0/GettingStarted.html"));
image1.setId("2");
image1
.setDescription("Rational Build Forge provides an adaptive process execution framework that automates, orchestrates, manages, and tracks all the processes between each handoff within the assembly line of software development, creating an automated software factory.");
@ -79,7 +78,8 @@ public class ParseImagesFromJsonTest {
Image image2 = new Image();
image2.setName("Rational Requirements Composer");
image2
.setManifest("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{28C7B870-2C0A-003F-F886-B89F5B413B77}/1.0/parameters.xml");
.setManifest(HttpUtils
.createUri("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{28C7B870-2C0A-003F-F886-B89F5B413B77}/1.0/parameters.xml"));
image2.setState(1);
image2.setVisibility(Image.Visibility.PUBLIC);
image2.setOwner("mutdosch@us.ibm.com");
@ -90,7 +90,8 @@ public class ParseImagesFromJsonTest {
image2.setSupportedInstanceTypes(ImmutableSet.of("LARGE", "MEDIUM"));
// image.setProductCodes();
image2
.setDocumentation("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{28C7B870-2C0A-003F-F886-B89F5B413B77}/1.0/GettingStarted.html");
.setDocumentation(HttpUtils
.createUri("https://www-180.ibm.com/cloud/enterprise/beta/ram.ws/RAMSecure/artifact/{28C7B870-2C0A-003F-F886-B89F5B413B77}/1.0/GettingStarted.html"));
image2.setId("10005598");
image2
.setDescription("Rational Requirements Composer helps teams define and use requirements effectively across the project lifecycle.");