Skip to content

Commit

Permalink
[FAB-3220] sync compositekey api w/ go
Browse files Browse the repository at this point in the history
ChaincodeStub:
 - getCompositeKey()
 - splitCompositKey()
CompositeKey:
 - new class
 - new unit tests

Change-Id: I697b7bb02b61a4b8acb5a086580e0ae34405a8c1
Signed-off-by: Luis Sanchez <sanchezl@us.ibm.com>
  • Loading branch information
Luis Sanchez committed Apr 26, 2017
1 parent 2318b8d commit 708c3aa
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 13 deletions.
2 changes: 2 additions & 0 deletions core/chaincode/shim/java/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ dependencies {
compile 'io.grpc:grpc-all:0.13.2'
compile 'commons-cli:commons-cli:1.3.1'
compile 'io.netty:netty-tcnative-boringssl-static:1.1.33.Fork21:' + tcnative_classifier
testCompile 'junit:junit:4.12'
testCompile 'org.hamcrest:hamcrest-library:1.3'
}

publishing {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent;
import org.hyperledger.fabric.protos.peer.ProposalResponsePackage.Response;
import org.hyperledger.fabric.shim.ledger.CompositeKey;

public interface ChaincodeStub {

Expand All @@ -43,7 +44,7 @@ public interface ChaincodeStub {
* @return a list of arguments cast to UTF-8 strings
*/
List<String> getStringArgs();

/**
* A convenience method that returns the first argument of the chaincode
* invocation for use as a function name.
Expand All @@ -53,7 +54,7 @@ public interface ChaincodeStub {
* @return the function name
*/
String getFunction();

/**
* A convenience method that returns all except the first argument of the
* chaincode invocation for use as the parameters to the function returned
Expand Down Expand Up @@ -117,14 +118,22 @@ public interface ChaincodeStub {
*
* @param objectType
* @param attributes
* @return
* @return a composite key
*/
String createCompositeKey(String objectType, String[] attributes);
CompositeKey createCompositeKey(String objectType, String... attributes);

/**
* Parses a composite key from a string.
*
* @param compositeKey a composite key string
* @return a composite key
*/
CompositeKey splitCompositeKey(String compositeKey);

/**
* Defines the CHAINCODE type event that will be posted to interested
* clients when the chaincode's result is committed to the ledger.
*
*
* @param name
* Name of event. Cannot be null or empty string.
* @param payload
Expand Down Expand Up @@ -220,4 +229,4 @@ default void putStringState(String key, String value) {
*/
ChaincodeEvent getEvent();

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent;
import org.hyperledger.fabric.protos.peer.ProposalResponsePackage.Response;
import org.hyperledger.fabric.shim.ledger.CompositeKey;

import com.google.protobuf.ByteString;

Expand Down Expand Up @@ -133,17 +134,21 @@ public void putState(String key, byte[] value) {
public void delState(String key) {
handler.handleDeleteState(key, txid);
}

/* (non-Javadoc)
* @see org.hyperledger.fabric.shim.ChaincodeStub#createCompositeKey(java.lang.String, java.lang.String[])
*/
@Override
public String createCompositeKey(String objectType, String[] attributes) {
String compositeKey = new String();
compositeKey = compositeKey + objectType;
for (String attribute : attributes) {
compositeKey = compositeKey + attribute.length() + attribute;
}
return compositeKey;
public CompositeKey createCompositeKey(String objectType, String... attributes) {
return new CompositeKey(objectType, attributes);
}

/* (non-Javadoc)
* @see org.hyperledger.fabric.shim.ChaincodeStub#splitCompositeKey(java.lang.String)
*/
@Override
public CompositeKey splitCompositeKey(String compositeKey) {
return CompositeKey.parseCompositeKey(compositeKey);
}

/* (non-Javadoc)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
Copyright IBM 2017 All Rights Reserved.
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.hyperledger.fabric.shim.ledger;

import static java.util.stream.Collectors.joining;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CompositeKey {

private static final String DELIMITER = new String(Character.toChars(Character.MIN_CODE_POINT));
private static final String INVALID_SEGMENT_CHAR = new String(Character.toChars(Character.MAX_CODE_POINT));
private static final String INVALID_SEGMENT_PATTERN = String.format("(?:%s|%s)", INVALID_SEGMENT_CHAR, DELIMITER);

final String objectType;
final List<String> attributes;
final String compositeKey;

public CompositeKey(String objectType, String... attributes) {
this(objectType, attributes == null ? Collections.emptyList() : Arrays.asList(attributes));
}

public CompositeKey(String objectType, List<String> attributes) {
if (objectType == null)
throw new NullPointerException("objectType cannot be null");
this.objectType = objectType;
this.attributes = attributes;
this.compositeKey = generateCompositeKeyString(objectType, attributes);
}

public String getObjectType() {
return objectType;
}

public List<String> getAttributes() {
return attributes;
}

@Override
public String toString() {
return compositeKey;
}

public static CompositeKey parseCompositeKey(String compositeKey) {
if(compositeKey == null) return null;
final String[] segments = compositeKey.split(DELIMITER, 0);
return new CompositeKey(segments[0], Arrays.stream(segments).skip(1).toArray(String[]::new));
}

private String generateCompositeKeyString(String objectType, List<String> attributes) {

// object type must be a valid composite key segment
validateCompositeKeySegment(objectType);

// the attributes must be valid composite key segments
attributes.stream().forEach(x -> validateCompositeKeySegment(x));

// return objectType + DELIMITER + (attribute + DELIMITER)*
return attributes.stream().collect(joining(DELIMITER, objectType + DELIMITER, DELIMITER));

}

private void validateCompositeKeySegment(String segment) {
final Matcher matcher = Pattern.compile(INVALID_SEGMENT_PATTERN).matcher(segment);
if (matcher.find()) {
throw CompositeKeyFormatException.forInputString(segment, matcher.group(), matcher.start());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright IBM 2017 All Rights Reserved.
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.hyperledger.fabric.shim.ledger;

class CompositeKeyFormatException extends IllegalArgumentException {
private static final long serialVersionUID = 1L;

private CompositeKeyFormatException() {
super();
}

private CompositeKeyFormatException(String message, Throwable cause) {
super(message, cause);
}

private CompositeKeyFormatException(String s) {
super(s);
}

private CompositeKeyFormatException(Throwable cause) {
super(cause);
}

static CompositeKeyFormatException forInputString(String s, String group, int index) {
return new CompositeKeyFormatException(String.format("For input string '%s', found 'U+%06X' at index %d.", s, group.codePointAt(0), index));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
Copyright IBM 2017 All Rights Reserved.
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.hyperledger.fabric.shim.ledger;

import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.util.Arrays;

import org.junit.Test;

public class CompositeKeyTest {

@Test
public void testCompositeKeyStringStringArray() {
final CompositeKey key = new CompositeKey("abc", new String[] {"def", "ghi", "jkl", "mno"});
assertThat(key.getObjectType(), is(equalTo("abc")));
assertThat(key.getAttributes(), hasSize(4));
assertThat(key.toString(), is(equalTo("abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000")));
}

@Test
public void testCompositeKeyStringListOfString() {
final CompositeKey key = new CompositeKey("abc", Arrays.asList(new String[] {"def", "ghi", "jkl", "mno"}));
assertThat(key.getObjectType(), is(equalTo("abc")));
assertThat(key.getAttributes(), hasSize(4));
assertThat(key.toString(), is(equalTo("abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000")));
}

@Test(expected=CompositeKeyFormatException.class)
public void testCompositeKeyWithInvalidObjectTypeDelimiter() {
new CompositeKey("ab\u0000c", Arrays.asList(new String[] {"def", "ghi", "jkl", "mno"}));
}

@Test(expected=CompositeKeyFormatException.class)
public void testCompositeKeyWithInvalidAttributeDelimiter() {
new CompositeKey("abc", Arrays.asList(new String[] {"def", "ghi", "j\u0000kl", "mno"}));
}

@Test(expected=CompositeKeyFormatException.class)
public void testCompositeKeyWithInvalidObjectTypeMaxCodePoint() {
new CompositeKey("ab\udbff\udfffc", Arrays.asList(new String[] {"def", "ghi", "jkl", "mno"}));
}
@Test(expected=CompositeKeyFormatException.class)
public void testCompositeKeyWithInvalidAttributeMaxCodePoint() {
new CompositeKey("abc", Arrays.asList(new String[] {"def", "ghi", "jk\udbff\udfffl", "mno"}));
}

@Test
public void testGetObjectType() {
final CompositeKey key = new CompositeKey("abc", Arrays.asList(new String[] {"def", "ghi", "jkl", "mno"}));
assertThat(key.getObjectType(), is(equalTo("abc")));
}

@Test
public void testGetAttributes() {
final CompositeKey key = new CompositeKey("abc", Arrays.asList(new String[] {"def", "ghi", "jkl", "mno"}));
assertThat(key.getObjectType(), is(equalTo("abc")));
assertThat(key.getAttributes(), hasSize(4));
assertThat(key.getAttributes(), contains("def", "ghi", "jkl", "mno"));
}

@Test
public void testToString() {
final CompositeKey key = new CompositeKey("abc", Arrays.asList(new String[] {"def", "ghi", "jkl", "mno"}));
assertThat(key.toString(), is(equalTo("abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000")));
}

@Test
public void testParseCompositeKey() {
final CompositeKey key = CompositeKey.parseCompositeKey("abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000");
assertThat(key.getObjectType(), is(equalTo("abc")));
assertThat(key.getAttributes(), hasSize(4));
assertThat(key.getAttributes(), contains("def", "ghi", "jkl", "mno"));
assertThat(key.toString(), is(equalTo("abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000")));
}

@Test(expected=CompositeKeyFormatException.class)
public void testParseCompositeKeyInvalidObjectType() {
CompositeKey.parseCompositeKey("ab\udbff\udfffc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000");
}

@Test(expected=CompositeKeyFormatException.class)
public void testParseCompositeKeyInvalidAttribute() {
CompositeKey.parseCompositeKey("abc\u0000def\u0000ghi\u0000jk\udbff\udfffl\u0000mno\u0000");
}

}

0 comments on commit 708c3aa

Please sign in to comment.