org.dasein.cloud.aws.platform.SimpleDB.java Source code

Java tutorial

Introduction

Here is the source code for org.dasein.cloud.aws.platform.SimpleDB.java

Source

/**
 * Copyright (C) 2009-2015 Dell, Inc.
 * See annotations for authorship information
 *
 * ====================================================================
 * 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.dasein.cloud.aws.platform;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.annotation.Nonnull;

import org.apache.http.HttpStatus;
import org.apache.log4j.Logger;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.ResourceStatus;
import org.dasein.cloud.aws.AWSCloud;
import org.dasein.cloud.aws.compute.EC2Exception;
import org.dasein.cloud.aws.compute.EC2Method;
import org.dasein.cloud.identity.ServiceAction;
import org.dasein.cloud.platform.KeyValueDatabase;
import org.dasein.cloud.platform.KeyValueDatabaseCapabilities;
import org.dasein.cloud.platform.KeyValueDatabaseSupport;
import org.dasein.cloud.platform.KeyValuePair;
import org.dasein.cloud.util.APITrace;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class SimpleDB implements KeyValueDatabaseSupport {
    static private final Logger logger = AWSCloud.getLogger(SimpleDB.class);

    static public final String SERVICE_ID = "sdb";

    static public final String CREATE_DOMAIN = "CreateDomain";
    static public final String DELETE_ATTRIBUTES = "DeleteAttributes";
    static public final String DELETE_DOMAIN = "DeleteDomain";
    static public final String DOMAIN_META_DATA = "DomainMetadata";
    static public final String GET_ATTRIBUTES = "GetAttributes";
    static public final String LIST_DOMAINS = "ListDomains";
    static public final String PUT_ATTRIBUTES = "PutAttributes";
    static public final String SELECT = "Select";
    private volatile transient SimpleDBCapabilities capabilities;

    static public @Nonnull ServiceAction[] asSimpleDBServiceAction(@Nonnull String action) {
        if (action.equals(CREATE_DOMAIN)) {
            return new ServiceAction[] { KeyValueDatabaseSupport.CREATE_KVDB };
        } else if (action.equals(DELETE_DOMAIN)) {
            return new ServiceAction[] { KeyValueDatabaseSupport.REMOVE_KVDB };
        } else if (action.equals(LIST_DOMAINS)) {
            return new ServiceAction[] { KeyValueDatabaseSupport.LIST_KVDB, KeyValueDatabaseSupport.GET_KVDB };
        } else if (action.equals(SELECT)) {
            return new ServiceAction[] { KeyValueDatabaseSupport.SELECT };
        }
        return new ServiceAction[0];
    }

    private AWSCloud provider;

    SimpleDB(AWSCloud cloud) {
        provider = cloud;
    }

    @Override
    public void addKeyValuePairs(String inDomainId, String itemId, KeyValuePair... pairs)
            throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.addKeyValuePairs");
        try {
            if (pairs != null && pairs.length > 0) {
                Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                        PUT_ATTRIBUTES);
                EC2Method method;
                int i = 0;

                parameters.put("DomainName", inDomainId);
                parameters.put("ItemName", itemId);
                for (KeyValuePair pair : pairs) {
                    parameters.put("Attribute." + i + ".Name", pair.getKey());
                    parameters.put("Attribute." + i + ".Value", pair.getValue());
                    i++;
                }
                method = new EC2Method(SERVICE_ID, provider, parameters);
                try {
                    method.invoke();
                } catch (EC2Exception e) {
                    throw new CloudException(e);
                }
            }
        } finally {
            APITrace.end();
        }
    }

    @Override
    public String createDatabase(String name, String description) throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.createDatabase");
        try {
            Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                    CREATE_DOMAIN);
            EC2Method method;

            name = validateName(name);
            parameters.put("DomainName", name);
            method = new EC2Method(SERVICE_ID, provider, parameters);
            try {
                method.invoke();
            } catch (EC2Exception e) {
                throw new CloudException(e);
            }
            return name;
        } finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull KeyValueDatabaseCapabilities getCapabilities() throws InternalException, CloudException {
        if (capabilities == null) {
            capabilities = new SimpleDBCapabilities(provider);
        }
        return capabilities;
    }

    @Override
    public KeyValueDatabase getDatabase(String domainId) throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.getDatabase");
        try {
            Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                    DOMAIN_META_DATA);
            EC2Method method;
            Document doc;

            parameters.put("DomainName", domainId);
            method = new EC2Method(SERVICE_ID, provider, parameters);
            try {
                doc = method.invoke();
            } catch (EC2Exception e) {
                String code = e.getCode();

                if (code != null && code.equals("NoSuchDomain")) {
                    return null;
                }
                throw new CloudException(e);
            }
            KeyValueDatabase database = new KeyValueDatabase();

            database.setProviderOwnerId(provider.getContext().getAccountNumber());
            database.setProviderRegionId(provider.getContext().getRegionId());
            database.setProviderDatabaseId(domainId);
            database.setName(domainId);
            database.setDescription(domainId);
            NodeList blocks = doc.getElementsByTagName("DomainMetadataResult");
            if (blocks.getLength() > 0) {
                for (int i = 0; i < blocks.getLength(); i++) {
                    NodeList items = blocks.item(i).getChildNodes();

                    for (int j = 0; j < items.getLength(); j++) {
                        Node item = items.item(j);
                        String name = item.getNodeName();

                        if (name.equals("ItemCount")) {
                            if (item.hasChildNodes()) {
                                database.setItemCount(Integer.parseInt(item.getFirstChild().getNodeValue()));
                            }
                        } else if (name.equals("AttributeValueCount")) {
                            if (item.hasChildNodes()) {
                                database.setKeyValueCount(Integer.parseInt(item.getFirstChild().getNodeValue()));
                            }
                        } else if (name.equals("AttributeNameCount")) {
                            if (item.hasChildNodes()) {
                                database.setKeyCount(Integer.parseInt(item.getFirstChild().getNodeValue()));
                            }
                        } else if (name.equals("ItemNamesSizeBytes")) {
                            if (item.hasChildNodes()) {
                                database.setItemSize(Integer.parseInt(item.getFirstChild().getNodeValue()));
                            }
                        } else if (name.equals("AttributeValuesSizeBytes")) {
                            if (item.hasChildNodes()) {
                                database.setKeyValueSize(Integer.parseInt(item.getFirstChild().getNodeValue()));
                            }
                        } else if (name.equals("AttributeNamesSizeBytes")) {
                            if (item.hasChildNodes()) {
                                database.setKeySize(Integer.parseInt(item.getFirstChild().getNodeValue()));
                            }
                        }
                    }
                }
            }
            return database;
        } finally {
            APITrace.end();
        }
    }

    @Override
    public Iterable<KeyValuePair> getKeyValuePairs(String inDomainId, String itemId, boolean consistentRead)
            throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.getKeyValuePairs");
        try {
            Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                    GET_ATTRIBUTES);
            EC2Method method;
            Document doc;

            parameters.put("DomainName", inDomainId);
            parameters.put("ItemName", itemId);
            parameters.put("ConsistentRead", String.valueOf(consistentRead));
            method = new EC2Method(SERVICE_ID, provider, parameters);
            try {
                doc = method.invoke();
            } catch (EC2Exception e) {
                String code = e.getCode();

                if (code != null && code.equals("NoSuchDomain")) {
                    return null;
                }
                throw new CloudException(e);
            }
            ;
            ArrayList<KeyValuePair> pairs = new ArrayList<KeyValuePair>();

            NodeList blocks = doc.getElementsByTagName("Attribute");
            for (int i = 0; i < blocks.getLength(); i++) {
                Node node = blocks.item(i);

                if (node.hasChildNodes()) {
                    NodeList children = node.getChildNodes();
                    String key = null, value = null;

                    for (int j = 0; j < children.getLength(); j++) {
                        Node item = children.item(j);

                        if (item.hasChildNodes()) {
                            String nv = item.getFirstChild().getNodeValue();

                            if (item.getNodeName().equals("Name")) {
                                key = nv;
                            } else if (item.getNodeName().equals("Value")) {
                                value = nv;
                            }
                        }
                    }
                    if (key != null) {
                        pairs.add(new KeyValuePair(key, value));
                    }
                }
            }
            return pairs;
        } finally {
            APITrace.end();
        }
    }

    @Override
    @Deprecated
    public String getProviderTermForDatabase(Locale locale) {
        try {
            return getCapabilities().getProviderTermForDatabase(locale);
        } catch (InternalException e) {
        } catch (CloudException e) {
        }
        return "domain"; // legacy
    }

    private String getSimpleDBUrl() throws InternalException, CloudException {
        if (provider.getContext().getRegionId() == null
                || provider.getContext().getRegionId().equals("us-east-1")) {
            return ("https://sdb.amazonaws.com");
        }
        return ("https://sdb." + provider.getContext().getRegionId() + ".amazonaws.com");
    }

    @Override
    public boolean isSubscribed() throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.isSubscribed");
        try {
            Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                    LIST_DOMAINS);
            EC2Method method;

            method = new EC2Method(SERVICE_ID, provider, parameters);
            try {
                method.invoke();
                return true;
            } catch (EC2Exception e) {
                if (e.getStatus() == HttpStatus.SC_UNAUTHORIZED || e.getStatus() == HttpStatus.SC_FORBIDDEN) {
                    return false;
                }
                String code = e.getCode();

                if (code != null && (code.equals("SubscriptionCheckFailed") || code.equals("AuthFailure")
                        || code.equals("SignatureDoesNotMatch") || code.equals("InvalidClientTokenId")
                        || code.equals("OptInRequired"))) {
                    return false;
                }
                logger.warn(e.getSummary());
                if (logger.isDebugEnabled()) {
                    e.printStackTrace();
                }
                throw new CloudException(e);
            }
        } finally {
            APITrace.end();
        }
    }

    @Override
    @Deprecated
    public boolean isSupportsKeyValueDatabases() throws CloudException, InternalException {
        return getCapabilities().isSupportsKeyValueDatabases();
    }

    @Override
    public Iterable<String> list() throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.list");
        try {
            ArrayList<String> list = new ArrayList<String>();
            String marker = null;

            do {
                Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                        LIST_DOMAINS);
                EC2Method method;
                NodeList blocks;
                Document doc;

                if (marker != null) {
                    parameters.put("NextToken", marker);
                }
                method = new EC2Method(SERVICE_ID, provider, parameters);
                try {
                    doc = method.invoke();
                } catch (EC2Exception e) {
                    throw new CloudException(e);
                }
                marker = null;
                blocks = doc.getElementsByTagName("NextToken");
                if (blocks.getLength() > 0) {
                    for (int i = 0; i < blocks.getLength(); i++) {
                        Node item = blocks.item(i);

                        if (item.hasChildNodes()) {
                            marker = item.getFirstChild().getNodeValue().trim();
                        }
                    }
                    if (marker != null) {
                        break;
                    }
                }
                blocks = doc.getElementsByTagName("DomainName");
                for (int i = 0; i < blocks.getLength(); i++) {
                    Node name = blocks.item(i);

                    if (name.hasChildNodes()) {
                        String domain = name.getFirstChild().getNodeValue();

                        if (domain != null) {
                            list.add(domain);
                        }
                    }
                }
            } while (marker != null);
            return list;
        } finally {
            APITrace.end();
        }
    }

    @Override
    public Iterable<ResourceStatus> listKeyValueDatabaseStatus() throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.listKeyValueDatabaseStatus");
        try {
            ArrayList<ResourceStatus> list = new ArrayList<ResourceStatus>();
            String marker = null;

            do {
                Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                        LIST_DOMAINS);
                EC2Method method;
                NodeList blocks;
                Document doc;

                if (marker != null) {
                    parameters.put("NextToken", marker);
                }
                method = new EC2Method(SERVICE_ID, provider, parameters);
                try {
                    doc = method.invoke();
                } catch (EC2Exception e) {
                    throw new CloudException(e);
                }
                marker = null;
                blocks = doc.getElementsByTagName("NextToken");
                if (blocks.getLength() > 0) {
                    for (int i = 0; i < blocks.getLength(); i++) {
                        Node item = blocks.item(i);

                        if (item.hasChildNodes()) {
                            marker = item.getFirstChild().getNodeValue().trim();
                        }
                    }
                    if (marker != null) {
                        break;
                    }
                }
                blocks = doc.getElementsByTagName("DomainName");
                for (int i = 0; i < blocks.getLength(); i++) {
                    Node name = blocks.item(i);

                    if (name.hasChildNodes()) {
                        list.add(new ResourceStatus(name.getFirstChild().getNodeValue(), true));
                    }
                }
            } while (marker != null);
            return list;
        } finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull String[] mapServiceAction(@Nonnull ServiceAction action) {
        if (action.equals(KeyValueDatabaseSupport.ANY)) {
            return new String[] { EC2Method.SDB_PREFIX + "*" };
        } else if (action.equals(KeyValueDatabaseSupport.CREATE_KVDB)) {
            return new String[] { EC2Method.SDB_PREFIX + CREATE_DOMAIN };
        } else if (action.equals(KeyValueDatabaseSupport.DELETE)) {
            return new String[] { EC2Method.SDB_PREFIX + DELETE_DOMAIN };
        } else if (action.equals(KeyValueDatabaseSupport.GET_KVDB)) {
            return new String[] { EC2Method.SDB_PREFIX + LIST_DOMAINS };
        } else if (action.equals(KeyValueDatabaseSupport.LIST_KVDB)) {
            return new String[] { EC2Method.SDB_PREFIX + LIST_DOMAINS };
        } else if (action.equals(KeyValueDatabaseSupport.PUT)) {
            return new String[] { EC2Method.SDB_PREFIX + PUT_ATTRIBUTES };
        } else if (action.equals(KeyValueDatabaseSupport.REMOVE_KVDB)) {
            return new String[] { EC2Method.SDB_PREFIX + DELETE_DOMAIN };
        } else if (action.equals(KeyValueDatabaseSupport.SELECT)) {
            return new String[] { EC2Method.SDB_PREFIX + SELECT };
        }
        return new String[0];
    }

    @Override
    public Map<String, Set<KeyValuePair>> query(String queryString, boolean consistentRead)
            throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.query");
        try {
            Map<String, Set<KeyValuePair>> pairs = new HashMap<String, Set<KeyValuePair>>();
            String marker = null;

            do {
                Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                        SELECT);
                NodeList blocks;
                EC2Method method;
                Document doc;

                if (marker != null) {
                    parameters.put("NextToken", marker);
                }
                parameters.put("SelectExpression", queryString);
                parameters.put("ConsistentRead", String.valueOf(consistentRead));
                method = new EC2Method(SERVICE_ID, provider, parameters);
                try {
                    doc = method.invoke();
                } catch (EC2Exception e) {
                    String code = e.getCode();

                    if (code != null && code.equals("NoSuchDomain")) {
                        return null;
                    }
                    throw new CloudException(e);
                }
                marker = null;
                blocks = doc.getElementsByTagName("NextToken");
                if (blocks.getLength() > 0) {
                    for (int i = 0; i < blocks.getLength(); i++) {
                        Node item = blocks.item(i);

                        if (item.hasChildNodes()) {
                            marker = item.getFirstChild().getNodeValue().trim();
                        }
                    }
                    if (marker != null) {
                        break;
                    }
                }
                blocks = doc.getElementsByTagName("Item");
                for (int i = 0; i < blocks.getLength(); i++) {
                    Node item = blocks.item(i);

                    if (item.hasChildNodes()) {
                        TreeSet<KeyValuePair> itemPairs = new TreeSet<KeyValuePair>();
                        NodeList children = item.getChildNodes();
                        String itemId = null;

                        for (int j = 0; j < children.getLength(); j++) {
                            Node child = children.item(j);

                            if (child.hasChildNodes()) {
                                String nn = child.getNodeName();

                                if (nn.equals("Name")) {
                                    itemId = child.getFirstChild().getNodeValue();
                                } else if (nn.equals("Attribute")) {
                                    NodeList parts = child.getChildNodes();
                                    String key = null, value = null;

                                    for (int k = 0; k < parts.getLength(); k++) {
                                        Node part = parts.item(k);

                                        if (part.hasChildNodes()) {
                                            String nv = part.getFirstChild().getNodeValue();

                                            if (part.getNodeName().equals("Name")) {
                                                key = nv;
                                            } else if (part.getNodeName().equals("Value")) {
                                                value = nv;
                                            }
                                        }
                                    }
                                    if (key != null) {
                                        itemPairs.add(new KeyValuePair(key, value));
                                    }
                                }
                            }
                        }
                        if (itemId != null) {
                            pairs.put(itemId, itemPairs);
                        }
                    }
                }
            } while (marker != null);
            return pairs;
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void removeDatabase(String domainId) throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.removeDatabase");
        try {
            Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                    DELETE_DOMAIN);
            EC2Method method;

            parameters.put("DomainName", domainId);
            method = new EC2Method(SERVICE_ID, provider, parameters);
            try {
                method.invoke();
            } catch (EC2Exception e) {
                throw new CloudException(e);
            }
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void removeKeyValuePairs(String inDomainId, String itemId, KeyValuePair... pairs)
            throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.removeKeyValuePairs");
        try {
            if (pairs != null && pairs.length > 0) {
                Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                        DELETE_ATTRIBUTES);
                EC2Method method;
                int i = 0;

                parameters.put("DomainName", inDomainId);
                parameters.put("ItemName", itemId);
                for (KeyValuePair pair : pairs) {
                    parameters.put("Attribute." + i + ".Name", pair.getKey());
                    if (pair.getValue() != null) {
                        parameters.put("Attribute." + i + ".Value", pair.getValue());
                    }
                    i++;
                }
                method = new EC2Method(SERVICE_ID, provider, parameters);
                try {
                    method.invoke();
                } catch (EC2Exception e) {
                    throw new CloudException(e);
                }
            }
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void removeKeyValuePairs(String inDomainId, String itemId, String... pairs)
            throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.removeKeyValuePairStrings");
        try {
            if (pairs != null && pairs.length > 0) {
                Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                        DELETE_ATTRIBUTES);
                EC2Method method;
                int i = 0;

                parameters.put("DomainName", inDomainId);
                parameters.put("ItemName", itemId);
                for (String pair : pairs) {
                    parameters.put("Attribute." + i + ".Name", pair);
                    i++;
                }
                method = new EC2Method(SERVICE_ID, provider, parameters);
                try {
                    method.invoke();
                } catch (EC2Exception e) {
                    throw new CloudException(e);
                }
            }
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void replaceKeyValuePairs(String inDomainId, String itemId, KeyValuePair... pairs)
            throws CloudException, InternalException {
        APITrace.begin(provider, "KVDB.replaceKeyValuePairs");
        try {
            if (pairs != null && pairs.length > 0) {
                Map<String, String> parameters = provider.getStandardSimpleDBParameters(provider.getContext(),
                        PUT_ATTRIBUTES);
                EC2Method method;
                int i = 0;

                parameters.put("DomainName", inDomainId);
                parameters.put("ItemName", itemId);
                for (KeyValuePair pair : pairs) {
                    parameters.put("Attribute." + i + ".Name", pair.getKey());
                    parameters.put("Attribute." + i + ".Value", pair.getValue());
                    parameters.put("Attribute." + i + ".Replace", "true");
                    i++;
                }
                method = new EC2Method(SERVICE_ID, provider, parameters);
                try {
                    method.invoke();
                } catch (EC2Exception e) {
                    throw new CloudException(e);
                }
            }
        } finally {
            APITrace.end();
        }
    }

    private String validateName(String name) {
        StringBuilder str = new StringBuilder();

        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);

            if (Character.isLetterOrDigit(c)) {
                str.append(c);
            } else if (c == '-' || c == '_' || c == '.') {
                str.append(c);
            }
        }
        if (str.length() < 3) {
            if (str.length() < 2) {
                if (str.length() < 1) {
                    return "aaa";
                }
                return str.toString() + "aa";
            }
            return str.toString() + "a";
        } else if (str.length() > 255) {
            return str.toString().substring(0, 255);
        }
        return str.toString();
    }
}