org.hyperledger.fabric.sdk.Member Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fabric-java-sdk Show documentation
Show all versions of fabric-java-sdk Show documentation
This is a fork of Hyperledger Fabric fabric-sdk-java
/*
* Copyright 2016 DTCC, Fujitsu Australia Software Technology - 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.sdk;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.util.encoders.Hex;
import org.hyperledger.fabric.sdk.exception.DeploymentException;
import org.hyperledger.fabric.sdk.exception.EnrollmentException;
import org.hyperledger.fabric.sdk.exception.ChainCodeException;
import org.hyperledger.fabric.sdk.exception.NoValidPeerException;
import org.hyperledger.fabric.sdk.exception.RegistrationException;
import org.hyperledger.fabric.sdk.transaction.TransactionContext;
import org.hyperledger.protos.Fabric;
import io.netty.util.internal.StringUtil;
public class Member implements Serializable {
private static final long serialVersionUID = 8077132186383604355L;
private static final Log logger = LogFactory.getLog(Member.class);
private transient Chain chain;
private String name;
private ArrayList roles;
private String account;
private String affiliation;
private String enrollmentSecret;
private Enrollment enrollment = null;
private transient MemberServices memberServices;
private transient KeyValStore keyValStore;
private String keyValStoreName;
private Map tcertGetterMap;
private int tcertBatchSize;
/**
* Constructor for a member.
* @param name The member name
* A member who is neither registered nor enrolled.
*/
public Member(String name, Chain chain) {
if (chain == null) {
throw new IllegalArgumentException("A valid chain must be provided");
}
this.name = name;
this.chain = chain;
this.memberServices = chain.getMemberServices();
this.keyValStore = chain.getKeyValStore();
this.keyValStoreName = toKeyValStoreName(this.name);
this.tcertBatchSize = chain.getTCertBatchSize();
this.tcertGetterMap = new HashMap();
}
/**
* Get the member name.
* @return {string} The member name.
*/
public String getName() {
return this.name;
}
/**
* Get the chain.
* @return {Chain} The chain.
*/
public Chain getChain() {
return this.chain;
}
/**
* Get the member services.
* @return {MemberServices} The member services.
*/
public MemberServices getMemberServices() {
return this.memberServices;
}
/**
* Get the roles.
* @return {string[]} The roles.
*/
public ArrayList getRoles() {
return this.roles;
}
/**
* Set the roles.
* @param roles {string[]} The roles.
*/
public void setRoles(ArrayList roles) {
this.roles = roles;
}
/**
* Get the account.
* @return {string} The account.
*/
public String getAccount() {
return this.account;
}
/**
* Set the account.
* @param account The account.
*/
public void setAccount(String account) {
this.account = account;
}
/**
* Get the affiliation.
* @return {string} The affiliation.
*/
public String getAffiliation() {
return this.affiliation;
}
/**
* Set the affiliation.
* @param affiliation The affiliation.
*/
public void setAffiliation(String affiliation) {
this.affiliation = affiliation;
}
/**
* Get the transaction certificate (tcert) batch size, which is the number of tcerts retrieved
* from member services each time (i.e. in a single batch).
* @return The tcert batch size.
*/
public int getTCertBatchSize() {
if (this.tcertBatchSize <= 0) {
return this.chain.getTCertBatchSize();
} else {
return this.tcertBatchSize;
}
}
/**
* Set the transaction certificate (tcert) batch size.
* @param batchSize
*/
public void setTCertBatchSize(int batchSize) {
this.tcertBatchSize = batchSize;
}
/**
* Get the enrollment logger.info.
* @return {Enrollment} The enrollment.
*/
public Enrollment getEnrollment() {
return this.enrollment;
};
/**
* Determine if this name has been registered.
* @return {boolean} True if registered; otherwise, false.
*/
public boolean isRegistered() {
return this.isEnrolled() || !StringUtil.isNullOrEmpty(enrollmentSecret);
}
/**
* Determine if this name has been enrolled.
* @return {boolean} True if enrolled; otherwise, false.
*/
public boolean isEnrolled() {
return this.enrollment != null;
}
/**
* Register the member.
* @param registrationRequest the registration request
* @throws RegistrationException
*/
public void register(RegistrationRequest registrationRequest) throws RegistrationException {
if (!registrationRequest.getEnrollmentID().equals(getName())) {
throw new RuntimeException("registration enrollment ID and member name are not equal");
}
this.enrollmentSecret = memberServices.register(registrationRequest, chain.getRegistrar());
this.saveState();
}
/**
* Enroll the member and return the enrollment results.
* @param enrollmentSecret The password or enrollment secret as returned by register.
* @return enrollment details
* @throws EnrollmentException
*/
public Enrollment enroll(String enrollmentSecret) throws EnrollmentException {
EnrollmentRequest req = new EnrollmentRequest();
req.setEnrollmentID(getName());
req.setEnrollmentSecret(enrollmentSecret);
logger.debug(String.format("Enrolling [req=%s]", req));
this.enrollment = memberServices.enroll(req);
this.saveState();
return this.enrollment;
}
/**
* Perform both registration and enrollment.
* @throws RegistrationException
* @throws EnrollmentException
*/
public void registerAndEnroll(RegistrationRequest registrationRequest) throws RegistrationException, EnrollmentException {
register(registrationRequest);
enroll(this.enrollmentSecret);
}
/**
* Issue a deploy request on behalf of this member
* @param deployRequest {@link DeployRequest}
* @return {@link ChainCodeResponse} response to chain code deploy transaction
* @throws DeploymentException if the deployment fails.
*/
public ChainCodeResponse deploy(DeployRequest deployRequest) throws DeploymentException {
logger.debug("Member.deploy");
if (getChain().getPeers().isEmpty()) {
throw new NoValidPeerException(String.format("chain %s has no peers", getChain().getName()));
}
TransactionContext tcxt = this.newTransactionContext(null);
return tcxt.deploy(deployRequest);
}
/**
* Issue a invoke request on behalf of this member
* @param invokeRequest {@link InvokeRequest}
* @throws ChainCodeException if the chain code invocation fails
*/
public ChainCodeResponse invoke(InvokeRequest invokeRequest) throws ChainCodeException {
logger.debug("Member.invoke");
if (getChain().getPeers().isEmpty()) {
throw new NoValidPeerException(String.format("chain %s has no peers", getChain().getName()));
}
TransactionContext tcxt = this.newTransactionContext(null);
return tcxt.invoke(invokeRequest);
}
/**
* Issue a query request on behalf of this member.
* @param queryRequest {@link QueryRequest}
* @throws ChainCodeException if the query transaction fails
*/
public ChainCodeResponse query(QueryRequest queryRequest) throws ChainCodeException {
logger.debug("Member.query");
if (getChain().getPeers().isEmpty()) {
throw new NoValidPeerException(String.format("chain %s has no peers", getChain().getName()));
}
TransactionContext tcxt = this.newTransactionContext(null);
return tcxt.query(queryRequest);
}
/**
* Create a transaction context with which to issue build, deploy, invoke, or query transactions.
* Only call this if you want to use the same tcert for multiple transactions.
* @param tcert A transaction certificate from member services. This is optional.
* @return A transaction context.
*/
public TransactionContext newTransactionContext(TCert tcert) {
return new TransactionContext(this, tcert);
}
/**
* Get a user certificate.
* @param attrs The names of attributes to include in the user certificate.
*/
public void getUserCert(List attrs) {
this.getNextTCert(attrs);
}
/**
* Get the next available transaction certificate with the appropriate attributes.
*/
public TCert getNextTCert(List attrs) {
if (!isEnrolled()) {
throw new RuntimeException(String.format("user '%s' is not enrolled",this.getName()));
}
String key = getAttrsKey(attrs);
if (key == null) {
return null;
}
logger.debug(String.format("Member.getNextTCert: key=%s",key));
TCertGetter tcertGetter = this.tcertGetterMap.get(key);
if (tcertGetter == null) {
logger.debug(String.format("Member.getNextTCert: key=%s, creating new getter",key));
tcertGetter = new TCertGetter(this, attrs, key);
this.tcertGetterMap.put(key, tcertGetter);
}
return tcertGetter.getNextTCert();
}
private String getAttrsKey(List attrs ) {
if (attrs == null || attrs.isEmpty()) return null;
return String.join(",", attrs);
}
/**
* Save the state of this member to the key value store.
*/
public void saveState() {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
oos.flush();
keyValStore.setValue(keyValStoreName, Hex.toHexString(bos.toByteArray()));
bos.close();
} catch (IOException e) {
logger.debug(String.format("Could not save state of member %s", this.name), e);
}
}
/**
* Restore the state of this member from the key value store (if found). If not found, do nothing.
*/
public void restoreState() {
String memberStr = keyValStore.getValue(keyValStoreName);
if (null != memberStr) {
// The member was found in the key value store, so restore the
// state.
byte[] serialized = Hex.decode(memberStr);
ByteArrayInputStream bis = new ByteArrayInputStream(serialized);
try {
ObjectInputStream ois = new ObjectInputStream(bis);
Member state = (Member)ois.readObject();
if (state != null) {
this.name = state.name;
this.roles = state.roles;
this.account = state.account;
this.affiliation = state.affiliation;
this.enrollmentSecret = state.enrollmentSecret;
this.enrollment = state.enrollment;
} else {
logger.debug(String.format("Could not find member %s from keyvalue store", this.name));
}
} catch (IOException | ClassNotFoundException e) {
logger.debug(String.format("Could not restore state of member %s", this.name), e);
}
}
}
public String getEnrollmentSecret() {
return enrollmentSecret;
}
public void setEnrollmentSecret(String enrollmentSecret) {
this.enrollmentSecret = enrollmentSecret;
}
public void setEnrollment(Enrollment enrollment) {
this.enrollment = enrollment;
}
private String toKeyValStoreName(String name) {
return "member." + name;
}
}