org.xmlsh.aws.util.AWSDDBCommand.java Source code

Java tutorial

Introduction

Here is the source code for org.xmlsh.aws.util.AWSDDBCommand.java

Source

/**
 * $Id: $
 * $Date: $
 *
 */

package org.xmlsh.aws.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.stream.XMLStreamException;

import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.XdmItem;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.trans.XPathException;

import org.xmlsh.aws.util.DDBTypes.AttrType;
import org.xmlsh.aws.util.DDBTypes.IAttrNameExpr;
import org.xmlsh.aws.util.DDBTypes.IAttrObjectExpr;
import org.xmlsh.aws.util.DDBTypes.IAttrValueExpr;
import org.xmlsh.aws.util.DDBTypes.IKeyAttrValueMap;
import org.xmlsh.aws.util.DDBTypes.INameObjectMap;
import org.xmlsh.aws.util.DDBTypes.KeyAttrValueMap;
import org.xmlsh.core.InvalidArgumentException;
import org.xmlsh.core.Options;
import org.xmlsh.core.UnexpectedException;
import org.xmlsh.core.UnimplementedException;
import org.xmlsh.core.XValue;
import org.xmlsh.util.Base64;
import org.xmlsh.util.JavaUtils;
import org.xmlsh.util.Util;

import com.amazonaws.AmazonClientException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.PrimaryKey;
import com.amazonaws.services.dynamodbv2.document.spec.GetItemSpec;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.Capacity;
import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
import com.amazonaws.services.dynamodbv2.model.ConsumedCapacity;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndexDescription;
import com.amazonaws.services.dynamodbv2.model.ItemCollectionMetrics;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.LocalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.LocalSecondaryIndexDescription;
import com.amazonaws.services.dynamodbv2.model.Projection;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughputDescription;
import com.amazonaws.services.dynamodbv2.model.TableDescription;

public abstract class AWSDDBCommand extends AWSCommand<AmazonDynamoDBClient> {
    public static final String sATTR_NAME_EXPR_OPTIONS = "ne=attr-name-expr:+";
    public static final String sATTR_VALUE_EXPR_OPTIONS = "ve=attr-value-expr:+";

    public static final String sATTR_EXPR_OPTIONS = Options.joinOptions(sATTR_VALUE_EXPR_OPTIONS,
            sATTR_NAME_EXPR_OPTIONS);
    public static final String sTABLE_OPTIONS = "t=table:";
    public static final String sKEY_OPTIONS = "k=key:,kn=key-name:+,kv=key-value:+";
    public static final String sCONDITION_OPTIONS = "c=condition:";
    public static final String sRETURN_OPTIONS = "return=return-values:";
    public static final String sDDB_COMMON_OPTS = "q=quiet:,o+:";
    public static final String sDOCUMENT_OPTS = "document,j=json";
    public static final String sCONSISTANT_OPTS = "c=consistant";

    protected boolean bQuiet = false;

    static Object parseToJavaValue(String v) {
        if (v == null)
            return null;
        if (v.isEmpty())
            return v;
        Number num = JavaUtils.toNumber(v, null);
        if (num != null)
            return num;
        return v;
    }

    private DynamoDB mDynamo = null;
    private DynamoDBMapper mMapper = null;

    public static class RequestMetrics {
        public int count;
        public int scanCount;
        public ConsumedCapacity capacity;
        public ItemCollectionMetrics itemMetrics;

        public RequestMetrics(int count, int scanCount, ConsumedCapacity capacity) {
            super();
            this.count = count;
            this.scanCount = scanCount;
            this.capacity = capacity;
        }

        public RequestMetrics(ConsumedCapacity consumedCapacity, ItemCollectionMetrics itemCollectionMetrics) {
            count = 0;
            scanCount = 0;
            this.capacity = consumedCapacity;
            this.itemMetrics = itemCollectionMetrics;
        }
    }

    public AWSDDBCommand() {
        super();
    }

    @Override
    protected void parseCommonOptions(Options opts) {
        {
            super.parseCommonOptions(opts);
            bQuiet = opts.hasOpt("quiet");
        }

    }

    void binary(byte[] array) throws IOException {

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        Base64.OutputStream b64 = new Base64.OutputStream(os, Base64.ENCODE);
        b64.write(array);
        b64.close();

    }

    protected void getDDBClient(Options opts) throws UnexpectedException, InvalidArgumentException {
        setAmazon(AWSClientFactory.newDDBClient(mShell, opts));

    }

    @Override
    public int run(List<XValue> args) throws Exception {
        // TODO Auto-generated method stub
        return 0;
    }

    private void setDynamoDBOpts(Options options) {
    }

    protected DynamoDB getDynamotDB(Options opts) throws UnexpectedException, InvalidArgumentException {
        if (getAWSClient() == null)
            getDDBClient(opts);
        assert (getAWSClient() != null);
        if (mDynamo == null)
            mDynamo = new DynamoDB(getAWSClient());
        setDynamoDBOpts(opts);
        return mDynamo;
    }

    protected DynamoDBMapper getMapper(Options opts) throws UnexpectedException, InvalidArgumentException {
        if (getAWSClient() == null)
            getDDBClient(opts);
        assert (getAWSClient() != null);
        if (mMapper == null)
            mMapper = new DynamoDBMapper(getAWSClient());
        setMapperOpts(opts);
        return mMapper;
    }

    private void setMapperOpts(Options opts) {

    }

    protected AttributeDefinition parseKeyAttribute(XValue xv)
            throws InvalidArgumentException, UnexpectedException {
        DDBTypes.NameType ant = new DDBTypes.NameType(xv);
        return new AttributeDefinition().withAttributeName(ant.getName()).withAttributeType(ant.getTypeName());

    }

    // Parses one global secondary index
    protected GlobalSecondaryIndex parseGlobalSecondaryIndex(XValue xv)
            throws InvalidArgumentException, UnexpectedException {
        if (!xv.isXdmNode())
            throw new InvalidArgumentException(
                    "Unexpected argument type for global secondary index: " + xv.describe());

        GlobalSecondaryIndex gi = new GlobalSecondaryIndex();

        gi.setIndexName(xv.xpath(getShell(), "./@name").toString());
        gi.setKeySchema(parseKeySchemaList(xv.xpath(getShell(), "./key-schema")));
        gi.setProjection(parseProjection(xv.xpath(getShell(), "./projection")));
        gi.setProvisionedThroughput(parseProvisionedThroughput(xv.xpath(getShell(), "./provisioned-throughput")));

        return gi;
    }

    protected KeySchemaElement parseKeySchemaElement(XValue xv) throws InvalidArgumentException {

        // Note: overload of 'type' for hash/range
        DDBTypes.NameType ant = new DDBTypes.NameType(xv);
        KeySchemaElement keyElement = new KeySchemaElement().withAttributeName(ant.getName())
                .withKeyType(KeyType.valueOf(ant.getTypeName().toUpperCase()));
        return keyElement;
    }

    private Collection<KeySchemaElement> parseKeySchemaList(XValue xv)
            throws UnexpectedException, InvalidArgumentException {
        Collection<KeySchemaElement> list = new ArrayList<KeySchemaElement>();
        if (xv.isXdmNode()) {
            // value->sequence->item
            for (XdmItem item : xpath(xv, "key-schema/key-element-name").toXdmValue()) {
                if (item instanceof XdmNode) {
                    DDBTypes.NameType ant = new DDBTypes.NameType((XdmNode) item);
                    list.add(new KeySchemaElement(ant.getName(), ant.getTypeName()));
                } else
                    throw new UnexpectedException("Unexpected node type: " + item.getClass().getName());
            }
        } else
            throw new UnexpectedException("Unexpected type: " + xv.describe());
        return list;

    }

    protected LocalSecondaryIndex parseLocalSecondaryIndex(XValue xv)
            throws InvalidArgumentException, UnexpectedException {

        if (!xv.isXdmNode())
            throw new InvalidArgumentException(
                    "Unexpected argument type for global secondary index: " + xv.describe());
        XdmNode node = xv.asXdmNode();
        if (!node.getNodeName().getLocalName().equals("local-secondary-index"))
            throw new InvalidArgumentException(
                    "Unexpected element: " + node.getNodeName().toString() + " expected: local-secondary-index");

        LocalSecondaryIndex li = new LocalSecondaryIndex()
                .withIndexName(node.getAttributeValue(new QName("index-name")));

        li.setKeySchema(parseKeySchemaList(xpath(xv, "./key-schema")));
        return li;

    }

    private Projection parseProjection(XValue xv) throws UnexpectedException, InvalidArgumentException {
        if (xv.isXdmNode()) {
            XdmNode node = xv.asXdmNode();
            if (!node.getNodeName().getLocalName().equals("projection"))
                throw new UnexpectedException("unexpected element name: " + node.getNodeName().toString());

            Projection p = new Projection().withProjectionType(node.getAttributeValue(new QName("projection-type")))
                    .withNonKeyAttributes(xpath(xv, "./non-key-attribute/string()").asStringList());
            return p;
        } else
            throw new UnexpectedException("Unexpected type: " + xv.describe());

    }

    private ProvisionedThroughput parseProvisionedThroughput(XValue xpath) {
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.xmlsh.aws.util.AWSCommand#setRegion(java.lang.String)
     */

    /*
    @Override
    public void setRegionXXX(String region) {
    if( Util.isBlank(region) ||   super.hasSetEndpoint())
        return ;
    if( region.equals("local"))
        setEndpoint("http://localhost:8000");
    else
      mAmazon.setRegion(RegionUtils.getRegion(region));
        
    }
    */
    protected void writeAttribute(String key, AttributeValue avalue) throws XMLStreamException, IOException {

        startElement("attribute");
        attribute("name", key);
        writeAttributeValue(avalue);

        endElement();
    }

    protected void writeAttributeValue(AttributeValue avalue) throws XMLStreamException, IOException {
        if (avalue.getS() != null) {
            attribute(AttrType.S);
            characters(avalue.getS());
        } else if (avalue.getN() != null) {
            attribute(AttrType.N);
            characters(avalue.getN());
        } else

        if (avalue.getB() != null) {
            attribute(AttrType.B);
            binary(avalue.getB().array());
        } else if (avalue.getSS() != null) {
            attribute(AttrType.SS);

            for (String s : avalue.getSS()) {
                startElement("value");
                characters(s);
                endElement();
            }

        } else if (avalue.getNS() != null) {
            attribute(AttrType.NS);

            for (String s : avalue.getNS()) {
                startElement("value");
                characters(s);
                endElement();
            }
        } else if (avalue.getBS() != null) {
            attribute(AttrType.BS);

            for (ByteBuffer s : avalue.getBS()) {
                startElement("value");
                binary(s.array());
                endElement();
            }
        } else if (avalue.getL() != null) {
            attribute(AttrType.L);
            for (AttributeValue av : avalue.getL()) {
                startElement("value");
                writeAttributeValue(av);
                endElement();
            }
        } else if (avalue.getM() != null) {
            attribute(AttrType.M);
            for (Entry<String, AttributeValue> e : avalue.getM().entrySet()) {
                writeAttribute(e.getKey(), e.getValue());
            }
        } else if (avalue.isBOOL() != null) {
            attribute(AttrType.BOOL);
            characters(avalue.getBOOL().booleanValue() ? "true" : "false");
        } else if (avalue.isNULL() != null) {
            attribute(AttrType.NULL);
            characters(avalue.getNULL().booleanValue() ? "true" : "false");
        }

    }

    protected void attribute(AttrType t) throws XMLStreamException {
        attribute("type", t.name());
    }

    private void writeAttributeDefinition(AttributeDefinition def) throws XMLStreamException {
        startElement("attribute-definition");
        attribute("name", def.getAttributeName());
        attribute("type", def.getAttributeType());
        endElement();
    }

    private void writeAttributeDefinitions(List<AttributeDefinition> attributeDefinitions)
            throws XMLStreamException {
        startElement("attribute-definitions");
        for (AttributeDefinition def : attributeDefinitions)
            writeAttributeDefinition(def);
        endElement();

    }

    private void writeGlobalSecondaryIndex(GlobalSecondaryIndexDescription index) throws XMLStreamException {

        startElement("global-secondary-index");
        attribute("index-name", index.getIndexName());
        attribute("index-size", index.getIndexSizeBytes());
        attribute("index-status", index.getIndexStatus());
        attribute("item-count", index.getItemCount());
        writeKeySchemaList(index.getKeySchema());
        writeProjection(index.getProjection());
        writeProvisionedThroughput(index.getProvisionedThroughput());
        endElement();

    }

    private void writeGlobalSecondaryIndexes(List<GlobalSecondaryIndexDescription> globalSecondaryIndexes)
            throws XMLStreamException {
        startElement("global-secondary-indexes");
        if (globalSecondaryIndexes != null)
            for (GlobalSecondaryIndexDescription index : globalSecondaryIndexes)
                writeGlobalSecondaryIndex(index);
        endElement();

    }

    private void writeKeySchemaList(List<KeySchemaElement> keySchema) throws XMLStreamException {

        startElement("key-schema");
        for (KeySchemaElement key : keySchema) {
            startElement("key-schema-element");
            attribute("name", key.getAttributeName());
            attribute("type", key.getKeyType());
            endElement();
        }

    }

    private void writeLocalSecondaryIndex(LocalSecondaryIndexDescription index) throws XMLStreamException {

        startElement("local-secondary-index");
        attribute("index-name", index.getIndexName());
        attribute("index-size", index.getIndexSizeBytes());
        attribute("item-count", index.getItemCount());

        writeKeySchemaList(index.getKeySchema());
        writeProjection(index.getProjection());
        endElement();

    }

    private void writeLocalSecondaryIndexes(List<LocalSecondaryIndexDescription> localSecondaryIndexes)
            throws XMLStreamException {
        startElement("local-secondary-indexes");
        if (localSecondaryIndexes != null)
            for (LocalSecondaryIndexDescription index : localSecondaryIndexes)
                writeLocalSecondaryIndex(index);
        endElement();

    }

    private void writeProjection(Projection projection) throws XMLStreamException {
        startElement("projection");
        attribute("projection-type", projection.getProjectionType());
        for (String s : projection.getNonKeyAttributes())
            textElement("non-key-attribute", s);

        endElement();

    }

    private void writeProvisionedThroughput(ProvisionedThroughputDescription provisionedThroughput)
            throws XMLStreamException {
        startElement("provisioned-throughput");
        attribute("last-decrease", provisionedThroughput.getLastDecreaseDateTime());
        attribute("last-increase", provisionedThroughput.getLastIncreaseDateTime());
        attribute("decreases-today", provisionedThroughput.getNumberOfDecreasesToday());
        attribute("read-capacity", provisionedThroughput.getReadCapacityUnits());
        attribute("write-capacity", provisionedThroughput.getWriteCapacityUnits());
        endElement();

    }

    protected void writeTableDescription(TableDescription tableDescription) throws XMLStreamException {
        startElement("table");
        attribute("name", tableDescription.getTableName());
        attribute("status", tableDescription.getTableStatus());
        attribute("create-date", Util.formatXSDateTime(tableDescription.getCreationDateTime()));
        attribute("item-count", tableDescription.getItemCount());
        attribute("size", tableDescription.getTableSizeBytes());
        attribute("item-count", tableDescription.getItemCount());

        writeAttributeDefinitions(tableDescription.getAttributeDefinitions());
        writeKeySchemaList(tableDescription.getKeySchema());
        writeLocalSecondaryIndexes(tableDescription.getLocalSecondaryIndexes());
        writeGlobalSecondaryIndexes(tableDescription.getGlobalSecondaryIndexes());
        writeProvisionedThroughput(tableDescription.getProvisionedThroughput());

    }

    protected void writeAttrNameValue(String elem, Map<String, AttributeValue> result)
            throws XMLStreamException, IOException {
        startElement(elem);
        for (Entry<String, AttributeValue> a : result.entrySet())
            this.writeAttribute(a.getKey(), a.getValue());
        endElement();
    }

    protected void writeItem(Map<String, AttributeValue> result) throws XMLStreamException, IOException {
        writeAttrNameValue("item", result);
    }

    protected IKeyAttrValueMap parseKeyOptions(Options opts)
            throws InvalidArgumentException, UnexpectedException, UnimplementedException, IOException {
        IKeyAttrValueMap keys = new KeyAttrValueMap();
        if (opts.hasOpt("key"))
            for (XValue k : opts.getOptValues("key"))
                keys.putAll(DDBTypes.parseKey(k));

        if (opts.hasOpt("key-name")) {
            List<XValue> keyValues = opts.getOptValues("key-value");
            int i = 0;
            for (XValue keyName : opts.getOptValues("key-name"))
                keys.putAll(DDBTypes.parseKey(keyName, keyValues.get(i++)));
        }
        return keys;
    }

    protected void writeItemCollectionMetrics(ItemCollectionMetrics itemCollectionMetrics)
            throws XMLStreamException, IOException {
        startElement("item-collection-metrics");
        writeAttrNameValue("item-collection-key", itemCollectionMetrics.getItemCollectionKey());
        for (Double r : itemCollectionMetrics.getSizeEstimateRangeGB()) {
            super.startElement("size");
            attribute("value", r);
            endElement();
        }
        endElement();
    }

    protected void writeConsumedCapacity(ConsumedCapacity consumedCapacity) throws XMLStreamException {
        if (consumedCapacity == null)
            return;
        startElement("consumed-capacity");
        attribute("total-units", consumedCapacity.getCapacityUnits());
        startElement("table");
        writeCapacity("table-name", consumedCapacity.getTableName(), consumedCapacity.getTable());
        endElement();
        startElement("local-secondary-indexes");
        for (Entry<String, Capacity> ce : consumedCapacity.getLocalSecondaryIndexes().entrySet())
            writeCapacity("index-name", ce.getKey(), ce.getValue());
        endElement();

        startElement("global-secondary-indexes");
        for (Entry<String, Capacity> ce : consumedCapacity.getGlobalSecondaryIndexes().entrySet())
            writeCapacity("index-name", ce.getKey(), ce.getValue());
        endElement();
        endElement();

    }

    private void writeCapacity(String attr, String attrValue, Capacity cap) throws XMLStreamException {
        attribute(attr, attrValue);
        attribute("capacity-units", cap.getCapacityUnits());
    }

    private void attribute(String localName, Double d) throws XMLStreamException {
        attribute(localName, d.toString());
    }

    protected void writeMetrics(ArrayList<RequestMetrics> metrics) throws XMLStreamException, IOException {
        startElement("request-metrics");
        for (RequestMetrics m : metrics) {
            writeMetric(m);
        }
        endElement();

    }

    public void writeMetric(RequestMetrics m) throws XMLStreamException, IOException {

        startElement("request-metric");
        attribute("count", m.count);
        attribute("scanCount", m.scanCount);
        if (m.capacity != null)
            writeConsumedCapacity(m.capacity);
        if (m.itemMetrics != null)
            writeItemCollectionMetrics(m.itemMetrics);

        endElement();
    }

    protected int handleException(AmazonClientException e) {
        if (e instanceof ConditionalCheckFailedException)
            return handleConditionException((ConditionalCheckFailedException) e);
        return super.handleException(e);
    }

    protected GetItemSpec parseGetItemSpec(Options opts) throws InvalidArgumentException, XPathException,
            UnexpectedException, UnimplementedException, IOException {
        GetItemSpec spec = new GetItemSpec().withPrimaryKey(getPrimaryKey(opts))
                .withConsistentRead(opts.hasOpt("consistant")).withNameMap(parseAttrNameExprs(opts));
        if (opts.hasRemainingArgs())
            spec.withProjectionExpression(Util.stringJoin(Util.toStringList(opts.getRemainingArgs()), ","));
        return spec;

    }

    private static PrimaryKey getPrimaryKey(Options opts) throws InvalidArgumentException, XPathException,
            UnexpectedException, UnimplementedException, IOException {
        INameObjectMap keys = DDBTypes.parseKeyValueObjectOptions(opts);
        PrimaryKey key = new PrimaryKey();
        for (Entry<String, Object> e : keys.entrySet())
            key.addComponent(e.getKey(), e.getValue());
        return key;
    }

    protected IAttrObjectExpr parseAttrValueObjectExprs(Options opts) throws InvalidArgumentException {
        return DDBTypes.parseAttrValueObjectExprs(opts);
    }

    protected IAttrNameExpr parseAttrNameExprs(Options opts)
            throws InvalidArgumentException, UnexpectedException, UnimplementedException, IOException {
        IAttrNameExpr exprs = DDBTypes.parseAttrNameExprs(opts);
        if (exprs == null || exprs.isEmpty())
            return exprs;
        return DDBTypes.addNamePrefix(exprs);
    }

    protected IAttrValueExpr parseAttrValueExprs(Options opts)
            throws InvalidArgumentException, UnexpectedException, UnimplementedException, IOException {
        IAttrValueExpr exprs = DDBTypes.parseAttrValueExprs(opts);
        if (exprs == null || exprs.isEmpty())
            return exprs;
        return DDBTypes.addValuePrefix(exprs);
    }

    protected int handleConditionException(ConditionalCheckFailedException ce) {
        mShell.printErr("Conditional check failed for " + getName() + ". retryable: " + ce.isRetryable());
        mShell.printErr(ce.getLocalizedMessage());
        mLogger.trace("Conditional check failed for " + getName(), ce);
        return ce.isRetryable() ? 2 : -1;
    }

    @Override
    protected String getCommonOpts() {
        return Options.joinOptions(AWSCommand.sCOMMON_OPTS, sDDB_COMMON_OPTS);
    }

}

//
//
// Copyright (C) 2008-2014 David A. Lee.
//
// The contents of this file are subject to the "Simplified BSD License" (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.opensource.org/licenses/bsd-license.php
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is: all this file.
//
// The Initial Developer of the Original Code is David A. Lee
//
// Portions created by (your name) are Copyright (C) (your legal entity). All
// Rights Reserved.
//
// Contributor(s): none.
//