blob: f6b23a935d6b5c833a2b9839fbad9761a7681c88 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.gora.dynamodb.store;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.amazonaws.services.dynamodb.model.KeySchema;
import com.amazonaws.services.dynamodb.model.KeySchemaElement;
import com.amazonaws.services.dynamodb.model.ProvisionedThroughput;
public class DynamoDBMapping {
/**
* Helper to write useful information into the logs
*/
public static final Logger LOG = LoggerFactory.getLogger(DynamoDBMapping.class);
/**
* a map from field name to attribute value
*/
private final Map<String, List<Map<String, String>>> tablesToItems;
/**
* Maps tables to their own key schemas
*/
private final Map<String, KeySchema> tablesToKeySchemas;
/**
* Maps tables to their provisioned throughput
*/
private final Map<String, ProvisionedThroughput> tablesToPrTh;
/**
* Constructor for DynamoDBMapping
* @param tables Tables mapped.
* @param tablesToKeySchemas KeySchemas used within tables mapped.
* @param provisionedThroughput Provisioned throughput used within tables mapped.
*/
public DynamoDBMapping(Map<String, List<Map<String, String>>> tables,
Map<String, KeySchema> tablesToKeySchemas,
Map<String, ProvisionedThroughput> provisionedThroughput) {
this.tablesToItems = tables;
this.tablesToKeySchemas = tablesToKeySchemas;
this.tablesToPrTh = provisionedThroughput;
}
/**
* Gets the tables with their own items
* @return tablesToItem HashMap
*/
public Map<String,List<Map<String, String>>> getTables(){
return tablesToItems;
}
/**
* Gets items or attributes from a specific table
* @param tableName Table name to determine which attributes to get
* @return
*/
public List<Map<String, String>> getItems(String tableName){
return tablesToItems.get(tableName);
}
/**
* Gets the key schema from a specific table
* @param tableName Table name to determine which key schema to get
* @return
*/
public KeySchema getKeySchema(String tableName) {
return tablesToKeySchemas.get(tableName);
}
/**
* Gets the provisioned throughput from a specific table
* @param tableName Table name to determine which provisioned throughput to get
* @return
*/
public ProvisionedThroughput getProvisionedThroughput(String tableName){
return tablesToPrTh.get(tableName);
}
/**
* A builder for creating the mapper. This will allow building a thread safe
* {@link DynamoDBMapping} using simple immutabilty.
*
*/
public static class DynamoDBMappingBuilder {
/**
* Table name to be used to build the DynamoDBMapping object
*/
private String tableName;
/**
* This data structure can hold several tables, with their own items.
* Map<TableName, List<Map<AttributeName,AttributeType>>
*/
private Map<String, List<Map<String, String>>> tablesToItems =
new HashMap<String, List<Map<String, String>>>();
/**
* Maps tables to key schemas
*/
private Map<String, KeySchema> tablesToKeySchemas = new HashMap<String, KeySchema>();
/**
* Maps tables to provisioned throughput
*/
private Map<String, ProvisionedThroughput> tablesToPrTh = new HashMap<String, ProvisionedThroughput>();
/**
* Sets table name
* @param tabName
*/
public void setTableName(String tabName){
tableName = tabName;
}
/**
* Gets the table name for which the table is being mapped
* @param tableName
* @return
*/
public String getTableName(String tableName){
return tableName;
}
/**
* Sets the provisioned throughput for the specified table
* @param tableName
* @param readCapUnits
* @param writeCapUnits
*/
public void setProvisionedThroughput(String tableName, long readCapUnits, long writeCapUnits){
ProvisionedThroughput ptDesc =
new ProvisionedThroughput().withReadCapacityUnits(readCapUnits).withWriteCapacityUnits(writeCapUnits);
tablesToPrTh.put(tableName, ptDesc);
}
/**
* Sets the hash range key schema for the specified table
* @param tableName
* @param rangeKeyName
* @param rangeKeyType
*/
public void setHashRangeKeySchema(String tableName, String rangeKeyName, String rangeKeyType){
KeySchema kSchema = tablesToKeySchemas.get(tableName);
if ( kSchema == null)
kSchema = new KeySchema();
KeySchemaElement rangeKeyElement = new KeySchemaElement().withAttributeName(rangeKeyName).withAttributeType(rangeKeyType);
kSchema.setRangeKeyElement(rangeKeyElement);
tablesToKeySchemas.put(tableName, kSchema);
}
/**
* Sets the hash key schema for the specified table
* @param tableName
* @param keyName
* @param keyType
*/
public void setHashKeySchema(String tableName, String keyName, String keyType){
KeySchema kSchema = tablesToKeySchemas.get(tableName);
if ( kSchema == null)
kSchema = new KeySchema();
KeySchemaElement hashKey = new KeySchemaElement().withAttributeName(keyName).withAttributeType(keyType);
kSchema.setHashKeyElement(hashKey);
tablesToKeySchemas.put(tableName, kSchema);
}
/**
* Checks if a table exists, and if doesn't exist it creates the new table.
* @param tableName
* @return The table identified by the parameter
*/
private List<Map<String, String>> getOrCreateTable(String tableName) {
List<Map<String, String>> items = tablesToItems.get(tableName);
if (items == null) {
items = new ArrayList<Map<String, String>>();
tablesToItems.put(tableName, items);
}
return items;
}
/**
* Gets the attribute for a specific item. The idea is to be able to get different items with different attributes.
* TODO This method is incomplete because the itemNumber might not be present and this would be a problem
* @param items
* @param itemNumber
* @return
*/
private HashMap<String, String> getOrCreateItemAttribs(List<Map<String, String>> items, int itemNumber){
HashMap<String, String> itemAttribs;
if (items.isEmpty())
items.add(new HashMap<String, String>());
itemAttribs = (HashMap<String, String>) items.get(itemNumber);
if (itemAttribs == null)
items.add(new HashMap<String, String>());
return (HashMap<String, String>) items.get(itemNumber);
}
/**
* Adds an attribute to an specific item
* @param tableName
* @param attributeName
* @param attrType
* @param itemNumber
*/
public void addAttribute(String tableName, String attributeName, String attrType, int itemNumber) {
// selecting table
List<Map<String, String>> items = getOrCreateTable(tableName);
// add attribute to item
HashMap<String, String> itemAttribs = getOrCreateItemAttribs(items, itemNumber);
itemAttribs.put(attributeName, attrType);
//items.add(itemAttribs);
// add item to table
//tablesToItems.put(tableName, items);
}
/**
* Method to verify whether or not the schemas have been initialized
* @return
*/
private String verifyAllKeySchemas(){
String wrongTable = "";
// if there are not tables defined
if (tablesToItems.isEmpty()) return "";
for(String tableName : tablesToItems.keySet()){
// if there are not schemas defined
if (tablesToKeySchemas.isEmpty()) return "";
if (!verifyKeySchema(tableName)) return "";
}
return wrongTable;
}
/**
* Verifies is a table has a key schema defined
* @param tableName Table name to determine which key schema to obtain
* @return
*/
private boolean verifyKeySchema(String tableName){
KeySchema kSchema = tablesToKeySchemas.get(tableName);
if (kSchema == null)
return false;
KeySchemaElement rangeKey = kSchema.getRangeKeyElement();
KeySchemaElement hashKey = kSchema.getHashKeyElement();
// A range key must have a hash key as well
if (rangeKey != null){
if (hashKey != null)
return true;
else
return false;
}
// A hash key may exist by itself
if (hashKey != null)
return true;
return false;
}
/**
* Constructs the DynamoDBMapping object
* @return A newly constructed mapping.
*/
public DynamoDBMapping build() {
if (tableName == null) throw new IllegalStateException("tableName is not specified");
// verifying items for at least a table
if (tablesToItems.isEmpty()) throw new IllegalStateException("No tables");
// verifying if key schemas have been properly defined
String wrongTableName = verifyAllKeySchemas();
if (!wrongTableName.equals("")) throw new IllegalStateException("no key schemas defined for table " + wrongTableName);
// Return the tableDescription and all the attributes needed
return new DynamoDBMapping(tablesToItems,tablesToKeySchemas, tablesToPrTh);
}
}
}