Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /* ************************************************************************
   #
   #  DivConq
   #
   #  http://divconq.com/
   #
   #  Copyright:
   #    Copyright 2014 eTimeline, LLC. All rights reserved.
   #
  #  License:
  #    See the license.txt file in the project's top-level directory for details.
  #
  #  Authors:
  #    * Andy White
  #
  ************************************************************************ */
  package divconq.struct;
  
  
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  
  import divconq.hub.Hub;
DivConq uses a specialized type system that provides type consistency across services (including web services), database fields and stored procedures, as well as scripting. All scalars (including primitives) and composites (collections) are wrapped by some subclass of Struct. Map collections are expressed by this class - records have fields and fields are a name value pair. This class is analogous to an Object in JSON but may contain type information as well, similar to Yaml. TODO link to blog entries.

Author(s):
Andy
  
  public class RecordStruct extends CompositeStruct implements IItemCollectionGroovyObject /*, JSObject */ {
  	// this defines valid field name pattern (same as json)
  	static protected final Pattern FIELD_NAME_PATTERN =
  			Pattern.compile("(^[a-zA-Z][a-zA-Z0-9\\$_\\-]*$)|(^[\\$_][a-zA-Z][a-zA-Z0-9\\$_\\-]*$)");
  
  	// TODO check field names inside of "set field" etc.
  	static public boolean validateFieldName(String v) {
  		if (StringUtil.isEmpty(v))
  			return false;
  
  	}	
  	
  	protected Map<String,FieldStructfields = new HashMap<String,FieldStruct>();
  
  	public DataType getType() {
  		if (this. != null)
  			return super.getType();
  
  		// implied only, not explicit
  		return ..getSchema().getType("AnyRecord");
  	}

Provide data type info (schema for fields) and a list of initial fields

Parameters:
type field schema
fields initial pairs
  
 	public RecordStruct(DataType typeFieldStruct... fields) {
 		super(type);
 		this.setField(fields);
 	}

Optionally provide a list of initial fields

Parameters:
fields initial pairs
 
 	public RecordStruct(FieldStruct... fields) {
 		this.setField(fields);
 	}
 	
 	/* (non-Javadoc)
 	 * @see divconq.struct.CompositeStruct#select(divconq.struct.PathPart[])
 	 */
 	public Struct select(PathPart... path) {
 		if (path.length == 0)
 			return this;
 		
 		PathPart part = path[0];
 		
 		if (!part.isField()) {			
 			OperationResult log = part.getLog();
 			
 			if (log != null
 				log.warnTr(504, this);
 			
 		}
 		
 		String fld = part.getField();
 		
 		if (!this..containsKey(fld)) {
 			//OperationResult log = part.getLog();
 			
 			//if (log != null) 
 			//	log.warnTr(505, fld);
 			
 		}
 		
 		Struct o = this.getField(fld);
 
 		if (path.length == 1) 
 			return (o != null) ? o : .;
 		
 		if (o instanceof CompositeStruct
 			return ((CompositeStruct)o).select(Arrays.copyOfRange(path, 1, path.length));		
 		
 		OperationResult log = part.getLog();
 		
 		if (log != null
 			log.warnTr(503, o);
 		
 	}
 	
 	/* (non-Javadoc)
 	 * @see divconq.struct.CompositeStruct#isEmpty()
 	 */
 	public boolean isEmpty() {
 		return (this..size() == 0);
 	}
 	
 	/* (non-Javadoc)
 	 * @see divconq.struct.builder.ICompositeOutput#toBuilder(divconq.struct.builder.ICompositeBuilder)
 	 */
 	public void toBuilder(ICompositeBuilder builderthrows BuilderStateException {
 		builder.startRecord();
 		
 		for (FieldStruct f : this..values()) 
 			f.toBuilder(builder);
 		
 		builder.endRecord();
 	}

Adds or replaces a list of fields within the record.

Parameters:
fields to add or replace
Returns:
a log of messages about success of the call
 
 	public OperationResult setField(FieldStruct... fields) {
 		
 		for (FieldStruct f : fields) {
 			Struct svalue = f.getValue();
 			
 			if (!f.prepped) {
 				// take the original value and convert to a struct, fields hold structures
 				Object value = f.orgvalue;
 				
 				if (value instanceof ICompositeBuilder)
 					value = ((ICompositeBuilder)value).toLocal();
 				
 				if (this. != null) {
 					Field fld = this..getField(f.getName());
 					
 					if (fld != null) {
 						Struct sv = fld.wrap(valueor);
 						
 						if (sv != null)
 							svalue = sv;
 					}
 				}
 				
 				if (svalue == null
 					svalue = Struct.objectToStruct(value); 
 				
 				f.setValue(svalue);
 				f.prepped = true;
 			}
 			
 			//FieldStruct old = this.fields.get(f.getName());
 			
 			//if (old != null)
 			//	old.dispose();
 			
 			this..put(f.getName(), f);
 		}
 		
 		return or;
 	}

Add or replace a specific field with a value.

Parameters:
name of field
value to store with field
Returns:
a log of messages about success of the call
 
 	public OperationResult setField(String nameObject value) {
 		return this.setField(new FieldStruct(namevalue));
 	}

Returns:
collection of all the fields this record holds
 
 		return this..values();
 	}

Parameters:
name of the field desired
Returns:
the struct for that field
 
 	public Struct getField(String name) {
 		if (!this..containsKey(name)) 
 			return null;
 		
 		FieldStruct fs = this..get(name);
 		
 		if (fs == null)
 			return null;
 		
 		return fs.value;
 	}

Parameters:
name of the field desired
Returns:
the struct for that field
 
 	public FieldStruct getFieldStruct(String name) {
 		if (!this..containsKey(name)) 
 			return null;
 		
 		return this..get(name);
 	}

Parameters:
from original name of the field
to new name for field
 
 	public void renameField(String fromString to) {
 		FieldStruct f = this..remove(from);
 		
 		if (f != null) {
 			f.setName(to);
 			this..put(tof);
 		}
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as an Object
 
 	public Object getFieldAsAny(String name) {
 		Struct st = this.getField(name);
 		
 		if (st == null)
 			return null;
 		
 		if (st instanceof ScalarStruct
 			return ((ScalarStruct)st).getGenericValue();
 		
 		if (st instanceof CompositeStruct
 			return ((CompositeStruct)st).toString();
 		
 		return null;
 	}

If the record has schema, lookup the schema for a given field.

Parameters:
name of the field desired
Returns:
field's schema
 
 	public DataType getFieldType(String name) {
 		// look first at the field value, if it has schema return
 		Struct fs = this.getField(name);
 		
 		if ((fs != null) && (fs.hasExplicitType()))
 				return fs.getType();
 		
 		// look next at this records schema
 		if (this. != null) {
 			Field fld = this..getField(name);
 			
 			if (fld != null)
 				return fld.getPrimaryType();
 		}
 		
 		// give up, we don't know the schema
 		return null;
 	}

Like getField, except if the field does not exist it will be created and added to the Record (unless that field name violates the schema).

Parameters:
name of the field desired
Returns:
log of messages from call plus the requested structure
 
 		FuncResult<Structfr = new FuncResult<Struct>();
 		
 		if (!this..containsKey(name)) {
 			Struct value = null;
 			
 			if (this. != null) {
 				Field fld = this..getField(name);
 				
 				if (fld != null
 					value = fld.create(fr);
 				else if (this..isAnyRecord()) 
 					value = .;
 			}
 			else
 				value = .;
 			
 			if (value != null) {
 				FieldStruct f = new FieldStruct(namevalue);
 				f.value = value;
 				this..put(namef);
 				
 				fr.setResult(value);
 			}
 		}
 		else {
 			Struct value = this.getField(name);
 			
 			if (value == null)
 				value = .;
 			
 			fr.setResult(value);
 		}
 		
 		return fr;
 	}

Parameters:
name of field
Returns:
true if field exists
 
 	public boolean hasField(String name) {
 		return this..containsKey(name);
 	}

Parameters:
name of field
Returns:
true if field does not exist or if field is string and its value is empty
 
 	public boolean isFieldEmpty(String name) {
 		Struct f = this.getField(name);
 		
 		if (f == null
 			return true;
 		
 		return f.isEmpty();
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as Integer (DivConq thinks of integers as 64bit)
 
 	public Long getFieldAsInteger(String name) {
 		return Struct.objectToInteger(this.getField(name));
 	}
 	
 	public long getFieldAsInteger(String namelong defaultval) {
 		Long x = Struct.objectToInteger(this.getField(name));
 		
 		if (x == null)
 			return defaultval;
 		
 		return x;
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as BigInteger
 
 		return Struct.objectToBigInteger(this.getField(name));
 	}
 	
 	public BigInteger getFieldAsBigInteger(String nameBigInteger defaultval) {
 		BigInteger x = Struct.objectToBigInteger(this.getField(name));
 		
 		if (x == null)
 			return defaultval;
 		
 		return x;
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as BigDecimal
 
 	public BigDecimal getFieldAsDecimal(String name) {
 		return Struct.objectToDecimal(this.getField(name));
 	}
 	
 	public BigDecimal getFieldAsDecimal(String nameBigDecimal defaultval) {
 		BigDecimal x = Struct.objectToDecimal(this.getField(name));
 		
 		if (x == null)
 			return defaultval;
 		
 		return x;
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as Boolean
 
 	public Boolean getFieldAsBoolean(String name) {
 		return Struct.objectToBoolean(this.getField(name));
 	}
 
 	public boolean getFieldAsBooleanOrFalse(String name) {
 		Boolean b = Struct.objectToBoolean(this.getField(name));
 		
 		return (b == null) ? false : b.booleanValue();
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as DateTime
 
 	public DateTime getFieldAsDateTime(String name) {
 		return Struct.objectToDateTime(this.getField(name));
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as BigDateTime
 
 		return Struct.objectToBigDateTime(this.getField(name));
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as Date
 
 	public LocalDate getFieldAsDate(String name) {
 		return Struct.objectToDate(this.getField(name));
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as Time
 
 	public LocalTime getFieldAsTime(String name) {
 		return Struct.objectToTime(this.getField(name));
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as a String
 
 	public String getFieldAsString(String name) {
 		return Struct.objectToString(this.getField(name));
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as Memory
 
 	public Memory getFieldAsBinary(String name) {
 		return Struct.objectToBinary(this.getField(name));
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as a Record
 
 		return Struct.objectToRecord(this.getField(name));
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as a List
 
 	public ListStruct getFieldAsList(String name) {
 		return Struct.objectToList(this.getField(name));
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as CompositeStruct
 
 		return Struct.objectToComposite(this.getField(name));
 	}

Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as Struct
 
 	public Struct getFieldAsStruct(String name) {
 		return Struct.objectToStruct(this.getField(name));
 	}
 	
     public <T extends Object> T getFieldAsStruct(String nameClass<T> type) {
     	Struct s = this.getField(name);
     	
           if (type.isAssignableFrom(s.getClass()))
                 return type.cast(s);
          
           return null;
     }
    
Unlike getField, this returns the value (inner) rather than struct wrapping the value.

Parameters:
name of the field desired
Returns:
field's "inner" value as Xml (will parse if value is string)
 
 	public XElement getFieldAsXml(String name) {
 		return Struct.objectToXml(this.getField(name));
 	}

Returns:
number of fields held by this record
 
 	public int getFieldCount() {
 		return this..size();
 	}
 	
 	/*
 	public String checkRequiredFields(String... fields) {
 		for (String fld : fields) {
 			if (this.isFieldBlank(fld))
 				return fld;
 		}
 		
 		return null;
 	}
 	
 	public String checkRequiredIfPresentFields(String... fields) {
 		for (String fld : fields) {
 			if (this.hasField(fld) && this.isFieldBlank(fld))
 				return fld;
 		}
 		
 		return null;
 	}
 	
 	public String checkFieldRange(String... fields) {
 		for (FieldStruct fld : this.getFields()) {
 			boolean fnd = false;
 			
 			for (String fname : fields) {
 				if (fld.getName().equals(fname)) {
 					fnd = true;
 					break;
 				}
 			}
 			
 			if (!fnd)
 				return fld.getName();
 		}
 		
 		return null;
 	}
 	*/

Parameters:
name of field to remove
 
 	public void removeField(String name) {
 		this..remove(name);
 	}
 
 	public Struct sliceField(String name) {
 		FieldStruct fld = this..get(name);
 		
 		this..remove(name);
 		
 		return fld.sliceValue();
 	}
 
     @Override
     protected void doCopy(Struct n) {
     	super.doCopy(n);
     	
     	RecordStruct nn = (RecordStruct)n;
     	
     	for (FieldStruct fld : this..values())
     		nn.setField(fld.deepCopy());
     }
     
 	public Struct deepCopy() {
 		RecordStruct cp = new RecordStruct();
 		this.doCopy(cp);
 		return cp;
 	}
 	
 	public RecordStruct deepCopyExclude(String... exclude) {
 		RecordStruct cp = new RecordStruct();
     	super.doCopy(cp);
     	
     	for (FieldStruct fld : this..values()) {
 			boolean fnd = false;
 			
 			for (String x : exclude)
 				if (fld.getName().equals(x)) {
 					fnd = true;
 					break;
 				}
 			
 			if (!fnd)
 				cp.setField(fld.deepCopy());				
 		}    	
 		
 		return cp;
 	}

Remove all child fields.
 
 	public void clear() {		
 		this..clear();
 	}
 	
 	public void operation(StackEntry stackXElement code) {
 		if ("Set".equals(code.getName())) {
 			this.clear();
 			
 			String json = stack.resolveValueToString(code.getText());
 			
 			if (StringUtil.isNotEmpty(json)) {
 				RecordStruct pjson = (RecordStruct) CompositeParser.parseJson(" { " + json + " } ").getResult();
 
 				this.copyFields(pjson);
 			}
 			
 			stack.resume();
 			return;
 		}
 
 		if ("SetField".equals(code.getName())) {
             String def = stack.stringFromElement(code"Type");
             String name = stack.stringFromElement(code"Name");
 			
 			if (StringUtil.isEmpty(name)) {
 				// TODO log
 				stack.resume();
 				return;
 			}
             
             Struct var = null;
             
             if (StringUtil.isNotEmpty(def))
             	var = stack.getActivity().createStruct(def);
 
 			if (code.hasAttribute("Value")) {
 		        Struct var3 = stack.refFromElement(code"Value");
 		        
 				if (var == null
 	            	var = stack.getActivity().createStruct(var3.getType().getId());					
 				
 				if (var instanceof ScalarStruct
 					((ScalarStructvar).adaptValue(var3);
 				else
 					var = var3;
 			}
             
 			if (var == null) {
 				stack.log().errorTr(520);
 				stack.resume();
 				return;
 			}
 			
 			this.setField(namevar);
 			stack.resume();
 			return;
 		}
 
 		if ("RemoveField".equals(code.getName())) {
 			String name = stack.stringFromElement(code"Name");
 			
 			if (StringUtil.isEmpty(name)) {
 				// TODO log
 				stack.resume();
 				return;
 			}
 			
 			this.removeField(name);
 			
 			stack.resume();
 			return;
 		}
 
 		if ("NewList".equals(code.getName())) {
 			String name = stack.stringFromElement(code"Name");
 			
 			if (StringUtil.isEmpty(name)) {
 				// TODO log
 				stack.resume();
 				return;
 			}
 			
 			this.removeField(name);
 			
 			this.setField(namenew ListStruct());
 			
 			stack.resume();
 			return;
 		}
 
 		if ("NewRecord".equals(code.getName())) {
 			String name = stack.stringFromElement(code"Name");
 			
 			if (StringUtil.isEmpty(name)) {
 				// TODO log
 				stack.resume();
 				return;
 			}
 			
 			this.removeField(name);
 			
 			this.setField(namenew RecordStruct());
 			
 			stack.resume();
 			return;
 		}
 
 		if ("HasField".equals(code.getName())) {
 			String name = stack.stringFromElement(code"Name");
 			
 			if (StringUtil.isEmpty(name)) {
 				// TODO log
 				stack.resume();
 				return;
 			}
 			
 	        String handle = stack.stringFromElement(code"Handle");
 			if (handle != null
 	            stack.addVariable(handlenew BooleanStruct(this.hasField(name)));
 			
 			stack.resume();
 			return;
 		}
 
 		if ("IsFieldEmpty".equals(code.getName())) {
 			String name = stack.stringFromElement(code"Name");
 			
 			if (StringUtil.isEmpty(name)) {
 				// TODO log
 				stack.resume();
 				return;
 			}
 			
 	        String handle = stack.stringFromElement(code"Handle");
 			if (handle != null
 	            stack.addVariable(handlenew BooleanStruct(this.isFieldEmpty(name)));
 			
 			stack.resume();
 			return;
 		}
 		
 		super.operation(stackcode);
 	}
 
 	public void copyFields(RecordStruct srcString... except) {
 		if (src != null)
 			for (FieldStruct fld : src.getFields()) {
 				boolean fnd = false;
 				
 				for (String x : except)
 					if (fld.getName().equals(x)) {
 						fnd = true;
 						break;
 					}
 				
 				if (!fnd)
 					this.setField(fld);				
 			}
 	}
 
 	public Iterable<StructgetItems() {
 		List<Stringtkeys = new ArrayList<String>();
 		
 		for (String key : this..keySet())
 			tkeys.add(key);
 
 		Collections.sort(tkeys);
 		
 		List<Structkeys = new ArrayList<Struct>();
 		
 		for (String key : tkeys)
 			keys.add(new StringStruct(key));
 		
 		return keys;
 	}
 	
 		return new ClassicIterableAdapter<Struct>(this.getItems());
 	}
 	
 	public boolean equals(Object obj) {
 		// TODO go deep
 		if (obj instanceof RecordStruct) {
 			RecordStruct data = (RecordStructobj;
 			
 			for (FieldStruct fld : this..values()) {
 				if (!data.hasField(fld.name))
 					return false;
 				
 				Struct ds = data.getField(fld.name);
 				Struct ts = fld.value;
 				
 				if ((ds == null) && (ts == null))
 					continue;
 				
 				if ((ds == null) && (ts != null))
 					return false;
 				
 				if ((ds != null) && (ts == null))
 					return false;
 				
 				if (!ts.equals(ds))
 					return false;
 			}
 			
 			// don't need to check match the other way around, we already know matching fields have good values  
 			for (FieldStruct fld : data.fields.values()) {
 				if (!this.hasField(fld.name))
 					return false;
 			}
 			
 			return true;
 		}
 		
 		return super.equals(obj);
 	}
 	
     public Object getProperty(String name) { 
 		Struct v = this.getField(name);
 		
 		if (v == null)
 			return null;
 		
 		if (v instanceof CompositeStruct)
 			return v;
 		
 		return ((ScalarStructv).getGenericValue();
     }
     
     public void setProperty(String nameObject value) { 
 		this.setField(namevalue);
     }
 
 	// TODO generate only on request
 	private transient MetaClass metaClass = null;
 
 	public void setMetaClass(MetaClass v) {
 		this. = v;
 	}
 	
 	public MetaClass getMetaClass() {
         if (this. == null
         	this. = InvokerHelper.getMetaClass(getClass());
         
         return this.;
 	}
 
 	public Object invokeMethod(String nameObject arg1) {
 		// is really an object array
 		Object[] args = (Object[])arg1;
 		
 		if (args.length > 0)
 			..println("G2: " + name + " - " + args[0]);
 		else
 			..println("G2: " + name);
 		
 		// TODO Auto-generated method stub
 		return null;
 	}
 	
 	/*
 	@Override
 	public boolean hasMember(String name) {
 		return this.hasField(name);
 	}
 	
 	@Override
 	public Object getMember(String name) {
 		// TODO there is probably a better way...
 		if ("getFieldAsInteger".equals(name)) {
 			return new AbstractJSObject() {
 				@Override
 				public Object call(Object thiz, Object... args) {
 					return RecordStruct.this.getFieldAsInteger((String)args[0]);		// TODO saftey
 				}
			};
		// TODO there is probably a better way...
		if ("cbTest".equals(name)) {
			return new AbstractJSObject() {
				@Override
				public Object call(Object thiz, Object... args) {
					System.out.println(args[0]);
					//ScriptFunction x = null;
					new Thread(() -> {
						try {
							((ScriptFunction)args[0]).getBoundInvokeHandle(args[0]).invoke(new RecordStruct(new FieldStruct("Data", "atad")));
						catch (Throwable x) {
							System.out.println("Invoke Error: " + x);
							x.printStackTrace();
					}).start();
					return null;
			};
		Struct v = this.getField(name);
		if (v instanceof CompositeStruct)
			return v;
		return ((ScalarStruct) v).getGenericValue();
	@Override
	public void removeMember(String name) {
		this.removeField(name);
	@Override
	public void setMember(String name, Object value) {
		this.setField(name, value);
	@Override
	public Collection<Object> values() {
		System.out.println("call to values...");
		return null;  //this.fields.values();  TODO
	@Override
	public Set<String> keySet() {
		System.out.println("call to keyset...");
		return this.fields.keySet();
	@Override
	public Object call(Object thiz, Object... args) {
		System.out.println("call to call... " + thiz);
		return null;  //super.call(thiz, args);  TODO
	@Override
	public Object eval(String s) {
		System.out.println("a");
		// TODO Auto-generated method stub
		return null;
	@Override
	public boolean isArray() {
		System.out.println("b");
		// TODO Auto-generated method stub
		return false;
	@Override
	public boolean isFunction() {
		System.out.println("c");
		// TODO Auto-generated method stub
		return false;
	@Override
	public Object newObject(Object... args) {
		System.out.println("d");
		// TODO Auto-generated method stub
		return null;
	@Override
	public String getClassName() {
		System.out.println("e");
		// TODO Auto-generated method stub
		return null;
	@Override
	public Object getSlot(int arg0) {
		System.out.println("f");
		// TODO Auto-generated method stub
		return null;
	@Override
	public boolean hasSlot(int arg0) {
		System.out.println("g");
		// TODO Auto-generated method stub
		return false;
	@Override
	public boolean isInstance(Object arg0) {
		System.out.println("h");
		// TODO Auto-generated method stub
		return false;
	@Override
	public boolean isInstanceOf(Object arg0) {
		System.out.println("i");
		// TODO Auto-generated method stub
		return false;
	@Override
	public boolean isStrictFunction() {
		System.out.println("j");
		// TODO Auto-generated method stub
		return false;
	@Override
	public void setSlot(int arg0, Object arg1) {
		System.out.println("k");
		// TODO Auto-generated method stub
	@Override
	public double toNumber() {
		System.out.println("l");
		// TODO Auto-generated method stub
		return 0;
	*/
New to GrepCode? Check out our FAQ X