/*
* Copyright 2014-2015 CyberVision, Inc.
*
* 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.kaaproject.avro.ui.shared;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
public class RecordField extends FqnField {
private static final long serialVersionUID = -2006331166074707248L;
private static final String FQN_FIELD = "fqn";
private static final String RECORD_NAMESPACE_FIELD = "recordNamespace";
private static final String RECORD_NAME_FIELD = "recordName";
private static final String DISPLAY_NAME_FIELD = "displayName";
private static final String DESCRIPTION_FIELD = "description";
private static final String VERSION_FIELD = "version";
private List<FormField> value;
private boolean isNull = true;
private boolean isTypeHolder = false;
private boolean isTypeConsumer = false;
private FqnValueChangeListener fqnValueChangeListener;
private VersionValueChangeListener versionValueChangeListener;
private ConsumedFqnValueChangeListener consumedFqnValueChangeListener;
public RecordField() {
super();
this.value = new ArrayList<>();
}
public RecordField(FormContext context,
String fieldName,
String displayName,
String schema,
boolean optional) {
super(context, fieldName, displayName, schema, optional);
this.value = new ArrayList<>();
}
public boolean isRoot() {
if (context != null && context.getRootRecord() != null) {
return this.id == context.getRootRecord().getId();
}
return false;
}
public void orderSchemaTypes() {
if (context != null) {
context.orderSchemaTypes();
}
}
public List<FormField> getValue() {
return value;
}
public List<FormField> getFieldsWithAccess(FieldAccess... accesses) {
List<FormField> result = new ArrayList<FormField>();
for (FormField field : value) {
for (FieldAccess access : accesses) {
if (field.getFieldAccess() == access) {
result.add(field);
break;
}
}
}
return result;
}
public List<FormField> getKeyIndexedFields() {
List<FormField> result = new ArrayList<FormField>();
List<FormField> activeFields = getFieldsWithAccess(FieldAccess.EDITABLE,
FieldAccess.READ_ONLY);
for (FormField field : activeFields) {
if (field.getKeyIndex() > -1) {
result.add(field);
}
}
Collections.sort(result, new Comparator<FormField>() {
@Override
public int compare(FormField o1, FormField o2) {
return o1.getKeyIndex() - o2.getKeyIndex();
}
});
return result;
}
public void setIsTypeHolder(boolean isTypeHolder) {
this.isTypeHolder = isTypeHolder;
}
public boolean isTypeHolder() {
return isTypeHolder;
}
public void setIsTypeConsumer(boolean isTypeConsumer) {
this.isTypeConsumer = isTypeConsumer;
}
public boolean isTypeConsumer() {
return isTypeConsumer;
}
public Fqn getDeclaredFqn() {
FormField nameField = getFieldByName(RECORD_NAME_FIELD);
FormField namespaceField = getFieldByName(RECORD_NAMESPACE_FIELD);
if (nameField != null && namespaceField != null) {
String name = ((StringField)nameField).getValue();
String namespace = ((StringField)namespaceField).getValue();
if (strIsEmpty(namespace) && !isRoot()
&& context != null && context.getRootRecord() != null
&& context.getRootRecord().getDeclaredFqn() != null) {
namespace = context.getRootRecord().getDeclaredFqn().getNamespace();
}
if (!strIsEmpty(name) && !strIsEmpty(namespace)) {
return new Fqn(namespace, name);
}
}
return null;
}
public FqnKey getConsumedFqnKey() {
FormField fqnField = getFieldByName(FQN_FIELD);
if (fqnField != null) {
return ((FqnReferenceField)fqnField).getValue();
}
return null;
}
public void updateConsumedFqnKey(FqnKey key) {
FormField fqnField = getFieldByName(FQN_FIELD);
if (fqnField != null) {
((FqnReferenceField)fqnField).setValue(key);
}
}
public String getDisplayNameFieldValue() {
FormField displayNameField = getFieldByName(DISPLAY_NAME_FIELD);
if (displayNameField != null) {
return ((StringField)displayNameField).getValue();
}
return null;
}
public void setDisplayNameFieldOptional(boolean optional) {
FormField displayNameField = getFieldByName(DISPLAY_NAME_FIELD);
if (displayNameField != null) {
displayNameField.setOptional(optional);
}
}
public String getDescriptionFieldValue() {
FormField descriptionField = getFieldByName(DESCRIPTION_FIELD);
if (descriptionField != null) {
return ((StringField)descriptionField).getValue();
}
return null;
}
public Integer getVersion() {
if (isRoot() && context.isCtlSchema()) {
FormField versionField = getFieldByName(VERSION_FIELD);
if (versionField != null) {
return ((VersionField)versionField).getValue();
}
}
return null;
}
public void updateVersion(Integer version) {
if (isRoot() && context.isCtlSchema()) {
FormField versionField = getFieldByName(VERSION_FIELD);
if (versionField != null) {
((VersionField)versionField).setValue(version);
}
}
}
public FormField getFieldByName(String name) {
if (!isNull) {
for (int i=0;i<value.size();i++) {
if (value.get(i).getFieldName().equals(name)) {
return value.get(i);
}
}
}
return null;
}
public FormField getFieldByType(FieldType type) {
if (!isNull) {
for (int i=0;i<value.size();i++) {
if (value.get(i).getFieldType() == type) {
return value.get(i);
}
}
}
return null;
}
public int getFieldIndex(String name) {
if (!isNull) {
for (int i=0;i<value.size();i++) {
if (value.get(i).getFieldName().equals(name)) {
return i;
}
}
}
return -1;
}
public void addField(FormField field) {
value.add(field);
field.setParentField(this);
isNull = false;
}
public void insertFieldAtIndex(FormField field, int index) {
if (!isNull && index > -1 && index <= value.size()) {
value.add(index, field);
field.setParentField(this);
}
}
public boolean removeFieldByName(String name) {
if (!isNull) {
int index = getFieldIndex(name);
if (index > -1) {
FormField field = value.remove(index);
if (field != null) {
field.dispose();
}
return true;
}
}
return false;
}
public boolean hideFieldByName(String name) {
if (!isNull) {
FormField field = getFieldByName(name);
if (field != null) {
field.setFieldAccess(FieldAccess.HIDDEN);
return true;
}
}
return false;
}
@Override
public String getDisplayString() {
String str = super.getDisplayString();
if (isNull) {
str += ": null";
} else {
List<FormField> fields = getKeyIndexedFields();
if (fields.isEmpty()) {
fields = getFieldsWithAccess(FieldAccess.EDITABLE, FieldAccess.READ_ONLY);
}
if (!fields.isEmpty()) {
str += ": { ";
for (int i=0;i<fields.size();i++) {
FormField field = fields.get(i);
if (i>0) {
str += ", ";
}
str += field.getDisplayString();
}
str += " }";
}
}
return str;
}
@Override
public FieldType getFieldType() {
return FieldType.RECORD;
}
@Override
public boolean isNull() {
return isNull;
}
@Override
public void finalizeMetadata() {
create();
}
@Override
public void disableOverride() {
super.disableOverride();
for (FormField field : value) {
field.disableOverride();
}
}
@Override
protected FormField createInstance() {
return new RecordField();
}
@Override
protected void copyFields(FormField cloned, boolean deepCopy) {
super.copyFields(cloned, deepCopy);
RecordField clonedRecordField = (RecordField)cloned;
clonedRecordField.isTypeHolder = isTypeHolder;
clonedRecordField.isTypeConsumer = isTypeConsumer;
if (deepCopy) {
for (FormField field : value) {
FormField clonedField = field.clone();
clonedField.setParentField(clonedRecordField);
clonedRecordField.value.add(clonedField);
}
clonedRecordField.isNull = false;
clonedRecordField.registerListeners();
}
}
public void create() {
if (isNull) {
RecordField recordField = context.getRecordMetadata(getFqn());
for (FormField field : recordField.getValue()) {
FormField newField = field.clone();
newField.setParentField(this);
value.add(newField);
}
if (isOverrideDisabled()) {
disableOverride();
}
isNull = false;
fireChanged();
registerListeners();
}
}
protected void registerListeners() {
if (isTypeHolder) {
fqnValueChangeListener = new FqnValueChangeListener(this);
FormField nameField = getFieldByName(RECORD_NAME_FIELD);
FormField namespaceField = getFieldByName(RECORD_NAMESPACE_FIELD);
if (nameField != null && namespaceField != null) {
nameField.addValueChangeListener(fqnValueChangeListener);
namespaceField.addValueChangeListener(fqnValueChangeListener);
if (isRoot()) {
namespaceField.setOptional(false);
}
}
if (isRoot() && context.isCtlSchema()) {
versionValueChangeListener = new VersionValueChangeListener(this);
FormField versionField = getFieldByName(VERSION_FIELD);
if (versionField != null) {
versionField.addValueChangeListener(versionValueChangeListener);
}
}
} else if (isTypeConsumer) {
context.registerTypeConsumer(this);
if (context.isCtlSchema()) {
consumedFqnValueChangeListener = new ConsumedFqnValueChangeListener(this);
FormField fqnField = getFieldByName(FQN_FIELD);
if (fqnField != null) {
fqnField.addValueChangeListener(consumedFqnValueChangeListener);
}
}
}
}
private void showAlert(String alert) {
FormField alertField = getFieldByType(FieldType.ALERT);
if (alertField != null) {
((AlertField)alertField).setValue(alert);
}
}
private void clearAlert() {
showAlert(null);
}
public static class FqnValueChangeListener extends ValueChangeListener {
private static final long serialVersionUID = -7766362467689033532L;
private RecordField recordField;
public FqnValueChangeListener() {
}
public FqnValueChangeListener(RecordField recordField) {
this.recordField = recordField;
}
@Override
public void onValueChanged(Object value) {
if (validateFqnAndVersion(recordField, true)) {
recordField.clearAlert();
recordField.context.updateTypeHolder(recordField);
}
}
}
public static class VersionValueChangeListener extends ValueChangeListener {
private static final long serialVersionUID = -7766362467689033532L;
private RecordField recordField;
public VersionValueChangeListener() {
}
public VersionValueChangeListener(RecordField recordField) {
this.recordField = recordField;
}
@Override
public void onValueChanged(Object value) {
if (validateFqnAndVersion(recordField, false)) {
recordField.clearAlert();
recordField.context.updateTypeHolder(recordField);
}
}
}
public static class ConsumedFqnValueChangeListener extends ValueChangeListener {
private static final long serialVersionUID = -3906282204505179394L;
private RecordField recordField;
public ConsumedFqnValueChangeListener() {
}
public ConsumedFqnValueChangeListener(RecordField recordField) {
this.recordField = recordField;
}
@Override
public void onValueChanged(Object value) {
recordField.context.updateCtlDependencies();
}
}
private static boolean validateFqnAndVersion(RecordField recordField, boolean checkVersion) {
Fqn fqn = recordField.getDeclaredFqn();
if (recordField.isRoot() && recordField.context.isCtlSchema()) {
Integer version = recordField.getVersion();
if (recordField.context.isFqnAlreadyDeclared(recordField.id, fqn, true)) {
recordField.showAlert("FQN '" + fqn.getFqnString() + "' is already declared!");
return false;
} else if (!recordField.context.checkIsVersionAvailable(fqn, version)) {
recordField.showAlert("FQN '" + fqn.getFqnString() + "' with version " + version.intValue() + " is already declared!");
return false;
}
if (checkVersion && version == null && fqn != null) {
version = recordField.context.getMaxVersion(fqn);
if (version != null) {
recordField.updateVersion(version.intValue()+1);
}
}
} else if (recordField.context.isFqnAlreadyDeclared(recordField.id, fqn, true)) {
recordField.showAlert("FQN '" + fqn.getFqnString() + "' is already declared!");
return false;
}
return true;
}
public boolean setNull() {
if (!isNull) {
if (context != null) {
if (isTypeHolder) {
if (!context.removeTypeHolder(this)) {
return false;
}
fqnValueChangeListener = null;
versionValueChangeListener = null;
} else if (isTypeConsumer) {
context.unregisterTypeConsumer(id);
consumedFqnValueChangeListener = null;
}
}
for (FormField field : value) {
field.dispose();
}
value.clear();
isNull = true;
fireChanged();
}
return true;
}
@Override
public void dispose() {
if (setNull()) {
super.dispose();
}
}
@Override
public boolean isValid() {
if (isOverride() && !isChanged()) {
return true;
} else if (isOptional()) {
if (!isNull) {
return valid();
} else {
return true;
}
} else {
return !isNull && valid();
}
}
@Override
protected boolean valid() {
boolean valid = true;
if (isTypeHolder) {
if (!validateFqnAndVersion(this, false)) {
valid = false;
} else {
clearAlert();
}
}
for (FormField field : value) {
valid &= field.isValid();
}
return valid;
}
@Override
public Iterator<FormField> iterator() {
return FormFieldIterator.concatItemWithCollection(this, value).iterator();
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + (isNull ? 1231 : 1237);
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
RecordField other = (RecordField) obj;
if (isNull != other.isNull)
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}