Sharing programming tips and tricks

If you need ssl certificate for only single EC2 instance, you need to use ELB to use AWS issued free certificate manager, which incurs ~$20 monthly cost. An alternative is to install free certificate by Let’sEncrypt on the nginx hosted on EC2 instance.

While uploading file to S3, we sometime need to store some metadata associated with a file, such as Content-Type, custom metadata etc. Content-Type metadata can be easily added as header while uploading to S3, but custom metadata needs a bit more work.

Here is the file upload flow for a mobile app:

Figure: File Upload flow from mobile app to S3

After uploading file, we have a lambda which scales the image to a specific dimension determined by a custom metadata: ‘imageType’ (business type, not content-type) associated with file.

I have not found any useful documentation on how to put the metadata programmatically while signing the url request. After trying out, I found the following solution.

While asking for pre-signed url from app, app sends the ‘imageType’ (profile/other etc) input. Backend takes that field and sends as user-metadata to S3 for signing in the following way using field: “x-amz-meta-image-type”

Simplest possible Java State Machine

This simple state machine consists of few dead simple contracts for defining constraints and actions along with single engine file of ~80 lines.

This code base also includes few example file to show how to implement the contracts.

Transition Rule

Transition rules are defined in the state enum which implements a simple interface. Look at the example code to see how to define the rules.

Every state in the state enum defines from which states this state can be reached and what are the preconditions(a list) to statisfy for the transition and it allows to define a set of actions while doing the transition after satisfying all the preconditions.

Below is an example to define rule

public enum BlogState implements State {
DRAFT {
@Override
public Map<State, ConstraintActionPair> getTransitions() {
return null;
}
},
DELETED {
@Override
public Map<State, ConstraintActionPair> getTransitions() {
Set stateActions = new HashSet<>();
stateActions.add(new PublishAction());
List stateConstraints = new ArrayList<>();
stateConstraints.add(new RoleConstraint());
ConstraintActionPair constraintActionPair =
new ConstraintActionPair<>(stateConstraints, stateActions);
Map<State, ConstraintActionPair> constraintActionPairMap = new HashMap<>();
//here the key is the state from which this state can be reached and
//the value is a pair of constraints and actions for that state
constraintActionPairMap.put(BlogState.DRAFT, constraintActionPair);
return constraintActionPairMap;
}
}
}

It indicates that state DELETED can only be reached from DRAFT, satisfying RoleConstraint and if satisfied, it executes Publish Action (just for example).

Transition Constraints

Constrains are classes implementing below simple contract. Constraints have access to old value, new value, old state, new state; making it easy to validate the business logic.

Action Order

Actions are executed in order. You can override getOrder() method to set order of action. Lower the order number means higher prioriy. But you are not required to override this method, by default all actions have same priority(100).

Blocking & Non-blocking

Some actions may be blocking i.e if exception is thrown, no other actions is executed. In case of non-blocking actions, if it thows exception, next actions are executed sequentially. You can define a task blocking/non-blocking by simply overriding isBlocking() method in the action class. Be default all actions are blocking.