package org.smartly.commons.network.socket.messages.multipart;
import org.smartly.commons.Delegates;
import org.smartly.commons.async.Async;
import org.smartly.commons.cryptograph.GUID;
import org.smartly.commons.util.CompareUtils;
import org.smartly.commons.util.DateUtils;
import org.smartly.commons.util.StringUtils;
import java.util.*;
/**
* Multipart Message aggregator.
*/
public class Multipart {
// --------------------------------------------------------------------
// e v e n t s
// --------------------------------------------------------------------
public static interface OnPartListener {
public void handle(Multipart sender, MultipartMessagePart part);
}
public static interface OnFullListener {
public void handle(Multipart sender);
}
public static interface OnTimeOutListener {
public void handle(Multipart sender);
}
// --------------------------------------------------------------------
// f i e l d s
// --------------------------------------------------------------------
private final Collection<OnPartListener> _listeners_OnPart;
private final Collection<OnFullListener> _listeners_OnFull;
private final String _uid;
private final long _creationDate;
private final List<MultipartMessagePart> _list;
private int _capacity;
private Object _userData; // custom data
private long _lastActivityDate;
//-- readonly from part --//
private MultipartInfo.MultipartInfoType _type;
private String _name;
private String _userToken;
// --------------------------------------------------------------------
// c o n s t r u c t o r
// --------------------------------------------------------------------
public Multipart(final int capacity) {
this(null, capacity);
}
public Multipart(final String uid, final int capacity) {
_uid = StringUtils.hasText(uid) ? uid : GUID.create();
_creationDate = System.currentTimeMillis();
_lastActivityDate = System.currentTimeMillis();
_list = Collections.synchronizedList(new ArrayList<MultipartMessagePart>(capacity));
_listeners_OnFull = Collections.synchronizedCollection(new ArrayList<OnFullListener>());
_listeners_OnPart = Collections.synchronizedCollection(new ArrayList<OnPartListener>());
_capacity = capacity;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName()).append("{");
sb.append("UID:").append(this.getUid());
sb.append(", ");
sb.append("Type:").append(this.getType());
sb.append(", ");
sb.append("Alive Time:").append(this.getAliveTime());
sb.append(", ");
sb.append("Part Count:").append(this.count());
sb.append(", ");
sb.append("Capacity:").append(this.getCapacity());
sb.append(", ");
sb.append("Is Full:").append(this.isFull());
sb.append(", ");
sb.append("Name:").append(this.getName());
sb.append("}");
return sb.toString();
}
@Override
public boolean equals(final Object obj) {
return (obj instanceof Multipart) &&
_uid.equalsIgnoreCase(((Multipart) obj).getUid());
}
@Override
public int hashCode() {
return _uid.hashCode();
}
@Override
protected void finalize() throws Throwable {
try {
_userData = null;
_listeners_OnFull.clear();
_listeners_OnPart.clear();
_list.clear();
} catch (Throwable ignored) {
}
super.finalize();
}
// --------------------------------------------------------------------
// p u b l i c
// --------------------------------------------------------------------
public String getUid() {
return _uid;
}
public Object getUserData() {
return _userData;
}
public void setUserData(final Object value) {
if (null != value) {
_userData = value;
}
}
public MultipartInfo.MultipartInfoType getType() {
return _type;
}
public String getName() {
return _name;
}
public String getUserToken() {
return _userToken;
}
public boolean isType(final MultipartInfo.MultipartInfoType type) {
return CompareUtils.equals(_type, type);
}
public boolean isTypeString() {
return this.isType(MultipartInfo.MultipartInfoType.String);
}
public boolean isTypeFile() {
return this.isType(MultipartInfo.MultipartInfoType.File);
}
public int getCapacity() {
return _capacity;
}
public boolean hasError() {
synchronized (_list) {
for (final MultipartMessagePart part : _list) {
if (part.hasError()) {
return true;
}
}
return false;
}
}
public Throwable getError() {
synchronized (_list) {
for (final MultipartMessagePart part : _list) {
if (part.hasError()) {
return part.getError();
}
}
return null;
}
}
public MultipartMessagePart[] getParts() {
synchronized (_list) {
Collections.sort(_list);
return _list.toArray(new MultipartMessagePart[_list.size()]);
}
}
public String[] getPartNames() {
synchronized (_list) {
final List<String> result = new LinkedList<String>();
Collections.sort(_list);
for (final MultipartMessagePart part : _list) {
result.add(part.getInfo().getPartName());
}
return result.toArray(new String[result.size()]);
}
}
public double getAliveTime() {
return System.currentTimeMillis() - _creationDate; // DateUtils.dateDiff(DateUtils.now(), _creationDate, DateUtils.MILLISECOND);
}
public double getExpirationTime() {
return System.currentTimeMillis() - _lastActivityDate; // DateUtils.dateDiff(DateUtils.now(), _lastActivityDate, DateUtils.MILLISECOND);
}
public boolean isExpired(final long millisecondsTimeout) {
return this.getExpirationTime() < millisecondsTimeout;
}
public boolean isFull() {
return _capacity == _list.size();
}
public int count() {
synchronized (_list) {
return _list.size();
}
}
public void add(final MultipartMessagePart part) {
synchronized (_list) {
if (!_list.contains(part) && !this.isFull()) {
// reset expiration timer
_lastActivityDate = System.currentTimeMillis();
// add uid to part
part.setUid(this.getUid());
// add part to internal list
_list.add(part);
// raise event
this.doOnPart(part);
// set parent properties from part
this.setProperties(part);
// check if full
this.checkCapacity();
}
}
}
// --------------------------------------------------------------------
// e v e n t
// --------------------------------------------------------------------
public void onPart(final OnPartListener listener) {
synchronized (_listeners_OnPart) {
_listeners_OnPart.add(listener);
}
}
public void onFull(final OnFullListener listener) {
synchronized (_listeners_OnFull) {
_listeners_OnFull.add(listener);
}
}
// --------------------------------------------------------------------
// p r i v a t e
// --------------------------------------------------------------------
private void checkCapacity() {
if (_list.size() >= _capacity) {
//-- call event listeners --//
this.doOnFull();
}
}
private void doOnFull() {
synchronized (_listeners_OnFull) {
for (final OnFullListener listener : _listeners_OnFull) {
Async.Action(new Delegates.Action() {
@Override
public void handle(Object... args) {
listener.handle((Multipart) args[0]);
}
}, this);
}
}
}
private void doOnPart(final MultipartMessagePart part) {
synchronized (_listeners_OnPart) {
for (final OnPartListener listener : _listeners_OnPart) {
Async.Action(new Delegates.Action() {
@Override
public void handle(Object... args) {
listener.handle((Multipart) args[0], (MultipartMessagePart) args[1]);
}
}, this, part);
}
}
}
private void setProperties(final MultipartMessagePart part) {
if (null != part) {
if (null == _type) {
_type = part.getInfo().getType();
}
if (null == _name) {
_name = part.getInfo().getParentName();
}
if (null == _userToken) {
_userToken = part.getUserToken();
}
}
}
}