//
// typica - A client library for Amazon Web Services
// Copyright (C) 2007 Xerox Corporation
//
// 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 com.xerox.amazonws.sdb;
import java.io.InputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBException;
import org.xml.sax.SAXException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.HttpException;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import com.xerox.amazonws.common.AWSException;
import com.xerox.amazonws.common.AWSQueryConnection;
import com.xerox.amazonws.typica.sdb.jaxb.Attribute;
import com.xerox.amazonws.typica.sdb.jaxb.DeleteAttributesResponse;
import com.xerox.amazonws.typica.sdb.jaxb.GetAttributesResponse;
import com.xerox.amazonws.typica.sdb.jaxb.PutAttributesResponse;
/**
* This class provides an interface with the Amazon SDB service. It provides methods for
* listing items and adding/removing attributes.
*
* @author D. Kavanagh
* @author developer@dotech.com
*/
public class Item extends AWSQueryConnection {
private static Log logger = LogFactory.getLog(Item.class);
private String domainName;
private String identifier;
protected Item(String identifier, String domainName, String awsAccessId,
String awsSecretKey, boolean isSecure, int port,
String server) throws SDBException {
super(awsAccessId, awsSecretKey, isSecure, server, port);
this.domainName = domainName;
this.identifier = identifier;
SimpleDB.setVersionHeader(this);
}
/**
* Gets the name of the identifier that is unique to this Item
*
* @return the id
*/
public String getIdentifier() {
return identifier;
}
/**
* Gets a map of all attributes for this item
*
* @return the map of attributes
* @throws SDBException wraps checked exceptions
*/
public List<ItemAttribute> getAttributes() throws SDBException {
return getAttributes((String)null);
}
/**
* Gets attributes of a given name. The parameter limits the results to those of
* the name given.
*
* @param attributeName a name that limits the results
* @return the list of attributes
* @throws SDBException wraps checked exceptions
* @deprecated this didn't work, so I don't expect anyone was using it anyway!
*/
public List<ItemAttribute> getAttributes(String attributeName) throws SDBException {
Map<String, String> params = new HashMap<String, String>();
params.put("DomainName", domainName);
params.put("ItemName", identifier);
if (attributeName != null) {
params.put("AttributeName.1", attributeName);
}
HttpGet method = new HttpGet();
try {
GetAttributesResponse response =
makeRequestInt(method, "GetAttributes", params, GetAttributesResponse.class);
List<ItemAttribute> ret = new ArrayList<ItemAttribute>();
List<Attribute> attrs = response.getGetAttributesResult().getAttributes();
for (Attribute attr : attrs) {
ret.add(createAttribute(attr));
}
return ret;
} catch (UnsupportedEncodingException ex) {
throw new SDBException(ex.getMessage(), ex);
}
}
/**
* Gets selected attributes. The parameter limits the results to those of
* the name(s) given.
*
* @param attributes name(s) that limits the results
* @return the list of attributes
* @throws SDBException wraps checked exceptions
*/
public List<ItemAttribute> getAttributes(List<String> attributes) throws SDBException {
return getAttributes(attributes, false);
}
/**
* Gets selected attributes. The parameter limits the results to those of
* the name(s) given.
*
* @param attributes name(s) that limits the results
* @param consistent if true, consistency is assured
* @return the list of attributes
* @throws SDBException wraps checked exceptions
*/
public List<ItemAttribute> getAttributes(List<String> attributes, boolean consistent) throws SDBException {
Map<String, String> params = new HashMap<String, String>();
params.put("DomainName", domainName);
params.put("ItemName", identifier);
int idx = 1;
if (attributes != null) {
for (String attr : attributes) {
params.put("AttributeName."+idx, attr);
idx++;
}
}
HttpGet method = new HttpGet();
if (consistent) {
params.put("ConsistentRead", "true");
}
try {
GetAttributesResponse response =
makeRequestInt(method, "GetAttributes", params, GetAttributesResponse.class);
List<ItemAttribute> ret = new ArrayList<ItemAttribute>();
List<Attribute> attrs = response.getGetAttributesResult().getAttributes();
for (Attribute attr : attrs) {
ret.add(createAttribute(attr));
}
return ret;
} catch (UnsupportedEncodingException ex) {
throw new SDBException(ex.getMessage(), ex);
}
}
/**
* Gets selected attributes. The parameter limits the results to those of
* the name(s) given.
*
* @param attributes name(s) that limits the results
* @return the list of attributes
* @throws SDBException wraps checked exceptions
*/
public Map<String, List<String>> getAttributesMap(List<String> attributes) throws SDBException {
Map<String, String> params = new HashMap<String, String>();
params.put("DomainName", domainName);
params.put("ItemName", identifier);
int idx = 1;
if (attributes != null) {
for (String attr : attributes) {
params.put("AttributeName."+idx, attr);
idx++;
}
}
HttpGet method = new HttpGet();
try {
GetAttributesResponse response =
makeRequestInt(method, "GetAttributes", params, GetAttributesResponse.class);
Map<String, List<String>> ret = new HashMap<String, List<String>>();
List<Attribute> attrs = response.getGetAttributesResult().getAttributes();
for (Attribute attr : attrs) {
String name = attr.getName().getValue();
String encoding = attr.getName().getEncoding();
if (encoding != null && encoding.equals("base64")) {
name = new String(Base64.decodeBase64(name.getBytes()), "UTF-8");
}
List<String> vals = ret.get(name);
if (vals == null) {
vals = new ArrayList<String>();
ret.put(name, vals);
}
String value = attr.getValue().getValue();
encoding = attr.getValue().getEncoding();
if (encoding != null && encoding.equals("base64")) {
value = new String(Base64.decodeBase64(value.getBytes()), "UTF-8");
}
vals.add(value);
}
return ret;
} catch (UnsupportedEncodingException ex) {
throw new SDBException(ex.getMessage(), ex);
}
}
/**
* Creates attributes for this item. Each item can have "replace" specified which
* indicates to replace the Attribute/Value or ad a new Attribute/Value.
* NOTE: if an attribute value is null, that attribute will be ignored.
*
* @param attributes list of attributes to add
* @throws SDBException wraps checked exceptions
*/
public SDBResult putAttributes(List<ItemAttribute> attributes) throws SDBException {
return putAttributes(attributes, null);
}
/**
* Creates attributes for this item. Each item can have "replace" specified which
* indicates to replace the Attribute/Value or ad a new Attribute/Value.
* NOTE: if an attribute value is null, that attribute will be ignored.
*
* @param attributes list of attributes to add
* @param conditions the conditions under which attributes should be put
* @throws SDBException wraps checked exceptions
*/
public SDBResult putAttributes(List<ItemAttribute> attributes, List<Condition> conditions) throws SDBException {
Map<String, String> params = new HashMap<String, String>();
params.put("DomainName", domainName);
params.put("ItemName", identifier);
int i=1;
for (ItemAttribute attr : attributes) {
String val = attr.getValue();
if (val != null) {
params.put("Attribute."+i+".Name", attr.getName());
params.put("Attribute."+i+".Value", val);
if (attr.isReplace()) {
params.put("Attribute."+i+".Replace", "true");
}
i++;
}
}
if (conditions != null) {
i=1;
for (Condition cond : conditions) {
params.put("Expected."+i+".Name", cond.getName());
String value = cond.getValue();
if (value != null) {
params.put("Expected."+i+".Value", value);
}
else {
params.put("Expected."+i+".Exists", cond.isExists()?"true":"false");
}
i++;
}
}
HttpGet method = new HttpGet();
PutAttributesResponse response =
makeRequestInt(method, "PutAttributes", params, PutAttributesResponse.class);
return new SDBResult(null,
response.getResponseMetadata().getRequestId(),
response.getResponseMetadata().getBoxUsage());
}
/**
* Deletes one or more attributes.
*
* @param attributes the names of the attributes to be deleted
* @throws SDBException wraps checked exceptions
*/
public SDBResult deleteAttributes(List<ItemAttribute> attributes) throws SDBException {
return deleteAttributes(attributes, null);
}
/**
* Deletes one or more attributes.
*
* @param attributes the names of the attributes to be deleted
* @param conditions the conditions under which the delete should happen
* @throws SDBException wraps checked exceptions
*/
public SDBResult deleteAttributes(List<ItemAttribute> attributes, List<Condition> conditions) throws SDBException {
Map<String, String> params = new HashMap<String, String>();
params.put("DomainName", domainName);
params.put("ItemName", identifier);
if (attributes != null) {
int i=1;
for (ItemAttribute attr : attributes) {
params.put("Attribute."+i+".Name", attr.getName());
String value = attr.getValue();
if (value != null) {
params.put("Attribute."+i+".Value", value);
}
i++;
}
}
if (conditions != null) {
int i=1;
for (Condition cond : conditions) {
params.put("Expected."+i+".Name", cond.getName());
String value = cond.getValue();
if (value != null) {
params.put("Expected."+i+".Value", value);
}
else {
params.put("Expected."+i+".Exists", cond.isExists()?"true":"false");
}
i++;
}
}
HttpGet method = new HttpGet();
DeleteAttributesResponse response =
makeRequestInt(method, "DeleteAttributes", params, DeleteAttributesResponse.class);
return new SDBResult(null,
response.getResponseMetadata().getRequestId(),
response.getResponseMetadata().getBoxUsage());
}
protected <T> T makeRequestInt(HttpRequestBase method, String action, Map<String, String> params, Class<T> respType)
throws SDBException {
try {
return makeRequest(method, action, params, respType);
} catch (AWSException ex) {
throw new SDBException(ex);
} catch (JAXBException ex) {
throw new SDBException("Problem parsing returned message.", ex);
} catch (SAXException ex) {
throw new SDBException("Problem parsing returned message.", ex);
} catch (HttpException ex) {
throw new SDBException(ex.getMessage(), ex);
} catch (IOException ex) {
throw new SDBException(ex.getMessage(), ex);
}
}
private ItemAttribute createAttribute(Attribute a) throws UnsupportedEncodingException {
String name = a.getName().getValue();
String encoding = a.getName().getEncoding();
if (encoding != null && encoding.equals("base64")) {
name = new String(Base64.decodeBase64(name.getBytes()), "UTF-8");
}
String value = a.getValue().getValue();
encoding = a.getValue().getEncoding();
if (encoding != null && encoding.equals("base64")) {
value = new String(Base64.decodeBase64(value.getBytes()), "UTF-8");
}
return new ItemAttribute(name, value, false);
}
}