Merry Christmas to the server CPUs. It occurred to me that we could

accomplish our "previous value" support in the distributed object system
without using reflection and could also avoid using reflection in the case
where we have already applied the event on the server (which is generally
the case on the server).

Rather than hacking up the gendobj script, I took this opportunity also to
rewrite the DObject generation script as an Ant task and in doing so,
implemented another recent idea which is that we can just augment the
FooObject.java file instead of having a separate .dobj and .java file.

You'd think it was spring there's so much cleaning going on.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3284 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2004-12-28 03:48:07 +00:00
parent bd80c348eb
commit 1d976ceaf8
13 changed files with 818 additions and 741 deletions
@@ -0,0 +1,405 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.presents.tools;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.util.ClasspathUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import com.samskivert.util.ObjectUtil;
import com.samskivert.util.SortableArrayList;
import com.samskivert.util.StringUtil;
import com.samskivert.velocity.VelocityUtil;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DSet;
import com.threerings.presents.dobj.OidList;
/**
* Generates necessary additional distributed object declarations and
* methods.
*/
public class GenDObjectTask extends Task
{
/**
* Adds a nested <fileset> element which enumerates service
* declaration source files.
*/
public void addFileset (FileSet set)
{
_filesets.add(set);
}
/** Configures our classpath which we'll use to load service classes. */
public void setClasspathref (Reference pathref)
{
_cloader = ClasspathUtils.getClassLoaderForPath(
getProject(), pathref);
}
/** Performs the actual work of the task. */
public void execute () throws BuildException
{
if (_cloader == null) {
String errmsg = "This task requires a 'classpathref' attribute " +
"to be set to the project's classpath.";
throw new BuildException(errmsg);
}
try {
_velocity = VelocityUtil.createEngine();
} catch (Exception e) {
throw new BuildException("Failure initializing Velocity", e);
}
// resolve the DObject class using our classloader
try {
_doclass = _cloader.loadClass(DObject.class.getName());
_dsclass = _cloader.loadClass(DSet.class.getName());
_olclass = _cloader.loadClass(OidList.class.getName());
} catch (Exception e) {
throw new BuildException("Can't resolve InvocationListener", e);
}
ArrayList files = new ArrayList();
for (Iterator iter = _filesets.iterator(); iter.hasNext(); ) {
FileSet fs = (FileSet)iter.next();
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
File fromDir = fs.getDir(getProject());
String[] srcFiles = ds.getIncludedFiles();
for (int f = 0; f < srcFiles.length; f++) {
processObject(new File(fromDir, srcFiles[f]));
}
}
}
/** Processes a distributed object source file. */
protected void processObject (File source)
{
// System.err.println("Processing " + source + "...");
// load up the file and determine it's package and classname
String name = null;
try {
name = GenUtil.readClassName(source);
} catch (Exception e) {
System.err.println(
"Failed to parse " + source + ": " + e.getMessage());
}
try {
processObject(source, _cloader.loadClass(name));
} catch (ClassNotFoundException cnfe) {
System.err.println(
"Failed to load " + name + ".\n" +
"Missing class: " + cnfe.getMessage());
System.err.println(
"Be sure to set the 'classpathref' attribute to a classpath\n" +
"that contains your projects invocation service classes.");
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
/** Processes a resolved distributed object class instance. */
protected void processObject (File source, Class oclass)
{
// make sure we extend distributed object
if (!_doclass.isAssignableFrom(oclass) || _doclass.equals(oclass)) {
// System.err.println("Skipping " + oclass.getName() + "...");
return;
}
// determine which fields we need to deal with
ArrayList flist = new ArrayList();
Field[] fields = oclass.getDeclaredFields();
for (int ii = 0; ii < fields.length; ii++) {
Field f = fields[ii];
int mods = f.getModifiers();
if (!Modifier.isPublic(mods) ||
Modifier.isStatic(mods) ||
Modifier.isTransient(mods)) {
continue;
}
flist.add(f);
}
// slurp our source file into newline separated strings
String[] lines = null;
try {
BufferedReader bin = new BufferedReader(new FileReader(source));
ArrayList llist = new ArrayList();
String line = null;
while ((line = bin.readLine()) != null) {
llist.add(line);
}
lines = (String[])llist.toArray(new String[llist.size()]);
bin.close();
} catch (IOException ioe) {
System.err.println("Error reading '" + source + "': " + ioe);
return;
}
// now determine where to insert our static field declarations and
// our generated methods
int bstart = -1, bend = -1;
int nstart = -1, nend = -1;
int mstart = -1, mend = -1;
for (int ii = 0; ii < lines.length; ii++) {
String line = lines[ii].trim();
// look for the start of the class body
if (GenUtil.NAME_PATTERN.matcher(line).find()) {
if (line.endsWith("{")) {
bstart = ii+1;
} else {
// search down a few lines for the open brace
for (int oo = 1; oo < 10; oo++) {
if (get(lines, ii+oo).trim().endsWith("{")) {
bstart = ii+oo+1;
break;
}
}
}
// track the last } on a line by itself and we'll call that
// the end of the class body
} else if (line.equals("}")) {
bend = ii;
// look for our field and method markers
} else if (line.equals(FIELDS_START)) {
nstart = ii;
} else if (line.equals(FIELDS_END)) {
nend = ii+1;
} else if (line.equals(METHODS_START)) {
mstart = ii;
} else if (line.equals(METHODS_END)) {
mend = ii+1;
}
}
// sanity check the markers
if (check(source, "fields start", nstart, "fields end", nend) ||
check(source, "fields end", nend, "fields start", nstart) ||
check(source, "methods start", mstart, "methods end", mend) ||
check(source, "methods end", mend, "methods start", mstart)) {
return;
}
// we have no previous markers then stuff the fields at the top of
// the class body and the methods at the bottom
if (nstart == -1) {
nstart = bstart;
nend = bstart;
}
if (mstart == -1) {
mstart = bend;
mend = bend;
}
// generate our fields section and our methods section
StringBuffer fsection = new StringBuffer();
StringBuffer msection = new StringBuffer();
for (int ii = 0; ii < flist.size(); ii++) {
Field f = (Field)flist.get(ii);
Class ftype = f.getType();
String fname = f.getName();
// create our velocity context
VelocityContext ctx = new VelocityContext();
ctx.put("field", fname);
ctx.put("type", GenUtil.simpleName(ftype));
ctx.put("wrapfield", GenUtil.boxArgument(ftype, "value"));
ctx.put("wrapofield", GenUtil.boxArgument(ftype, "ovalue"));
ctx.put("capfield", StringUtil.unStudlyName(fname).toUpperCase());
ctx.put("upfield", StringUtils.capitalize(fname));
if (ftype.isArray()) {
Class etype = ftype.getComponentType();
ctx.put("elemtype", GenUtil.simpleName(etype));
ctx.put("wrapelem", GenUtil.boxArgument(etype, "value"));
ctx.put("wrapoelem", GenUtil.boxArgument(etype, "ovalue"));
}
// now figure out which template to use
String tname = "field.tmpl";
if (_dsclass.isAssignableFrom(ftype)) {
tname = "set.tmpl";
} else if (_olclass.isAssignableFrom(ftype)) {
tname = "oidlist.tmpl";
}
// now generate our bits
StringWriter fwriter = new StringWriter();
StringWriter mwriter = new StringWriter();
try {
_velocity.mergeTemplate(NAME_TMPL, "UTF-8", ctx, fwriter);
_velocity.mergeTemplate(
BASE_TMPL + tname, "UTF-8", ctx, mwriter);
} catch (Exception e) {
System.err.println("Failed processing template");
e.printStackTrace(System.err);
}
// and append them as appropriate to the string buffers
if (ii > 0) {
fsection.append("\n");
msection.append("\n");
}
fsection.append(fwriter.toString());
msection.append(mwriter.toString());
}
// now bolt everything back together into a class declaration
try {
BufferedWriter bout = new BufferedWriter(new FileWriter(source));
for (int ii = 0; ii < nstart; ii++) {
writeln(bout, lines[ii]);
}
if (fsection.length() > 0) {
String prev = get(lines, nstart-1);
if (!StringUtil.blank(prev) && !prev.equals("{")) {
bout.newLine();
}
writeln(bout, " " + FIELDS_START);
bout.write(fsection.toString());
writeln(bout, " " + FIELDS_END);
if (!StringUtil.blank(get(lines, nend))) {
bout.newLine();
}
}
for (int ii = nend; ii < mstart; ii++) {
writeln(bout, lines[ii]);
}
if (msection.length() > 0) {
if (!StringUtil.blank(get(lines, mstart-1))) {
bout.newLine();
}
writeln(bout, " " + METHODS_START);
bout.write(msection.toString());
writeln(bout, " " + METHODS_END);
String next = get(lines, mend);
if (!StringUtil.blank(next) && !next.equals("}")) {
bout.newLine();
}
}
for (int ii = mend; ii < lines.length; ii++) {
writeln(bout, lines[ii]);
}
bout.close();
} catch (IOException ioe) {
System.err.println("Error writing to '" + source + "': " + ioe);
}
}
/** Safely gets the <code>index</code>th line, returning the empty
* string if we exceed the length of the array. */
protected String get (String[] lines, int index)
{
return (index < lines.length) ? lines[index] : "";
}
/** Helper function for sanity checking marker existence. */
protected boolean check (File source, String mname, int mline,
String fname, int fline)
{
if (mline == -1 && fline != -1) {
System.err.println("Found " + fname + " marker (at line " +
(fline+1) + ") but no " + mname +
" marker in '" + source + "'.");
return true;
}
return false;
}
/** Helper function for writing a string and a newline to a writer. */
protected void writeln (BufferedWriter bout, String line)
throws IOException
{
bout.write(line);
bout.newLine();
}
/** A list of filesets that contain tile images. */
protected ArrayList _filesets = new ArrayList();
/** Used to do our own classpath business. */
protected ClassLoader _cloader;
/** Used to generate source files from templates. */
protected VelocityEngine _velocity;
/** {@link DObject} resolved with the proper classloader so that we
* can compare it to loaded derived classes. */
protected Class _doclass;
/** {@link DSet} resolved with the proper classloader so that we can
* compare it to loaded derived classes. */
protected Class _dsclass;
/** {@link OidList} resolved with the proper classloader so that we
* can compare it to loaded derived classes. */
protected Class _olclass;
/** Specifies the start of the path to our various templates. */
protected static final String BASE_TMPL =
"com/threerings/presents/tools/dobject_";
/** Specifies the path to the name code template. */
protected static final String NAME_TMPL = BASE_TMPL + "name.tmpl";
// markers
protected static final String MARKER = "// AUTO-GENERATED: ";
protected static final String FIELDS_START = MARKER + "FIELDS START";
protected static final String FIELDS_END = MARKER + "FIELDS END";
protected static final String METHODS_START = MARKER + "METHODS START";
protected static final String METHODS_END = MARKER + "METHODS END";
}
@@ -70,7 +70,7 @@ public class GenServiceTask extends InvocationTask
public String getName ()
{
String name = simpleName(listener);
String name = GenUtil.simpleName(listener);
name = StringUtil.replace(name, "Listener", "");
int didx = name.indexOf(".");
return name.substring(didx+1);
@@ -118,7 +118,7 @@ public class GenServiceTask extends InvocationTask
Class[] args = m.getParameterTypes();
for (int aa = 0; aa < args.length; aa++) {
if (_ilistener.isAssignableFrom(args[aa]) &&
simpleName(args[aa]).startsWith(sname + ".")) {
GenUtil.simpleName(args[aa]).startsWith(sname + ".")) {
checkedAdd(listeners, new ServiceListener(
service, args[aa], imports));
}
@@ -0,0 +1,156 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.presents.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.samskivert.util.StringUtil;
/**
* Utility methods used by our various source code generating tasks.
*/
public class GenUtil
{
/** A regular expression for matching the package declaration. */
public static final Pattern PACKAGE_PATTERN =
Pattern.compile("^\\s*package\\s+(\\S+)\\W");
/** A regular expression for matching the class or interface
* declaration. */
public static final Pattern NAME_PATTERN =
Pattern.compile("^\\s*public\\s+(interface|class)\\s+(\\S+)(\\W|$)");
/**
* Returns the name of the supplied class as it would likely appear in
* code using the class (no package prefix, arrays specified as
* <code>type[]</code>).
*/
public static String simpleName (Class clazz)
{
if (clazz.isArray()) {
return simpleName(clazz.getComponentType()) + "[]";
} else {
Package pkg = clazz.getPackage();
int offset = (pkg == null) ? 0 : pkg.getName().length()+1;
String name = clazz.getName().substring(offset);
return StringUtil.replace(name, "$", ".");
}
}
/**
* "Boxes" the supplied argument, ie. turning an <code>int</code> into
* an <code>Integer</code> object.
*/
public static String boxArgument (Class clazz, String name)
{
if (clazz == Boolean.TYPE) {
return "new Boolean(" + name + ")";
} else if (clazz == Byte.TYPE) {
return "new Byte(" + name + ")";
} else if (clazz == Character.TYPE) {
return "new Character(" + name + ")";
} else if (clazz == Short.TYPE) {
return "new Short(" + name + ")";
} else if (clazz == Integer.TYPE) {
return "new Integer(" + name + ")";
} else if (clazz == Long.TYPE) {
return "new Long(" + name + ")";
} else if (clazz == Float.TYPE) {
return "new Float(" + name + ")";
} else if (clazz == Double.TYPE) {
return "new Double(" + name + ")";
} else {
return name;
}
}
/**
* "Unboxes" the supplied argument, ie. turning an
* <code>Integer</code> object into an <code>int</code>.
*/
public static String unboxArgument (Class clazz, String name)
{
if (clazz == Boolean.TYPE) {
return "((Boolean)" + name + ").booleanValue()";
} else if (clazz == Byte.TYPE) {
return "((Byte)" + name + ").byteValue()";
} else if (clazz == Character.TYPE) {
return "((Character)" + name + ").charValue()";
} else if (clazz == Short.TYPE) {
return "((Short)" + name + ").shortValue()";
} else if (clazz == Integer.TYPE) {
return "((Integer)" + name + ").intValue()";
} else if (clazz == Long.TYPE) {
return "((Long)" + name + ").longValue()";
} else if (clazz == Float.TYPE) {
return "((Float)" + name + ").floatValue()";
} else if (clazz == Double.TYPE) {
return "((Double)" + name + ").doubleValue()";
} else {
return "(" + simpleName(clazz) + ")" + name + "";
}
}
/**
* Reads in the supplied source file and locates the package and class
* or interface name and returns a fully qualified class name.
*/
public static String readClassName (File source)
throws IOException
{
// load up the file and determine it's package and classname
String pkgname = null, name = null;
BufferedReader bin = new BufferedReader(new FileReader(source));
String line;
while ((line = bin.readLine()) != null) {
Matcher pm = PACKAGE_PATTERN.matcher(line);
if (pm.find()) {
pkgname = pm.group(1);
}
Matcher nm = NAME_PATTERN.matcher(line);
if (nm.find()) {
name = nm.group(2);
break;
}
}
bin.close();
// make sure we found something
if (name == null) {
throw new IOException(
"Unable to locate class or interface name in " + source + ".");
}
// prepend the package name to get a name we can Class.forName()
if (pkgname != null) {
name = pkgname + "." + name;
}
return name;
}
}
@@ -3,7 +3,6 @@
package com.threerings.presents.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
@@ -15,9 +14,6 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@@ -58,7 +54,7 @@ public abstract class InvocationTask extends Task
public String getMarshaller ()
{
String name = simpleName(listener);
String name = GenUtil.simpleName(listener);
// handle ye olde special case
if (name.equals("InvocationService.InvocationListener")) {
return "ListenerMarshaller";
@@ -108,7 +104,7 @@ public abstract class InvocationTask extends Task
// InvocationService listeners, we need to import its
// marshaller as well
if (_ilistener.isAssignableFrom(arg) &&
!simpleName(arg).startsWith("InvocationService")) {
!GenUtil.simpleName(arg).startsWith("InvocationService")) {
String mname = arg.getName();
mname = StringUtil.replace(mname, "Service", "Marshaller");
mname = StringUtil.replace(mname, "Listener", "Marshaller");
@@ -131,7 +127,8 @@ public abstract class InvocationTask extends Task
if (buf.length() > 0) {
buf.append(", ");
}
buf.append(simpleName(args[ii])).append(" arg").append(ii+1);
buf.append(GenUtil.simpleName(args[ii]));
buf.append(" arg").append(ii+1);
}
return buf.toString();
}
@@ -144,7 +141,7 @@ public abstract class InvocationTask extends Task
if (buf.length() > 0) {
buf.append(", ");
}
buf.append(wrapArgument(args[ii], ii+1));
buf.append(boxArgument(args[ii], ii+1));
}
return buf.toString();
}
@@ -167,60 +164,28 @@ public abstract class InvocationTask extends Task
if (buf.length() > 0) {
buf.append(", ");
}
buf.append(unwrapArgument(args[ii], listenerMode ? ii : ii-1,
buf.append(unboxArgument(args[ii], listenerMode ? ii : ii-1,
listenerMode));
}
return buf.toString();
}
protected String wrapArgument (Class clazz, int index)
protected String boxArgument (Class clazz, int index)
{
if (clazz == Boolean.TYPE) {
return "new Boolean(arg" + index + ")";
} else if (clazz == Byte.TYPE) {
return "new Byte(arg" + index + ")";
} else if (clazz == Character.TYPE) {
return "new Character(arg" + index + ")";
} else if (clazz == Short.TYPE) {
return "new Short(arg" + index + ")";
} else if (clazz == Integer.TYPE) {
return "new Integer(arg" + index + ")";
} else if (clazz == Long.TYPE) {
return "new Long(arg" + index + ")";
} else if (clazz == Float.TYPE) {
return "new Float(arg" + index + ")";
} else if (clazz == Double.TYPE) {
return "new Double(arg" + index + ")";
} else if (_ilistener.isAssignableFrom(clazz)) {
return "listener" + index;
if (_ilistener.isAssignableFrom(clazz)) {
return GenUtil.boxArgument(clazz, "listener" + index);
} else {
return "arg" + index;
return GenUtil.boxArgument(clazz, "arg" + index);
}
}
protected String unwrapArgument (
protected String unboxArgument (
Class clazz, int index, boolean listenerMode)
{
if (clazz == Boolean.TYPE) {
return "((Boolean)args[" + index + "]).booleanValue()";
} else if (clazz == Byte.TYPE) {
return "((Byte)args[" + index + "]).byteValue()";
} else if (clazz == Character.TYPE) {
return "((Character)args[" + index + "]).charValue()";
} else if (clazz == Short.TYPE) {
return "((Short)args[" + index + "]).shortValue()";
} else if (clazz == Integer.TYPE) {
return "((Integer)args[" + index + "]).intValue()";
} else if (clazz == Long.TYPE) {
return "((Long)args[" + index + "]).longValue()";
} else if (clazz == Float.TYPE) {
return "((Float)args[" + index + "]).floatValue()";
} else if (clazz == Double.TYPE) {
return "((Double)args[" + index + "]).doubleValue()";
} else if (listenerMode && _ilistener.isAssignableFrom(clazz)) {
if (listenerMode && _ilistener.isAssignableFrom(clazz)) {
return "listener" + index;
} else {
return "(" + simpleName(clazz) + ")args[" + index + "]";
return GenUtil.unboxArgument(clazz, "args[" + index + "]");
}
}
}
@@ -294,35 +259,9 @@ public abstract class InvocationTask extends Task
{
// System.err.println("Processing " + source + "...");
// load up the file and determine it's package and classname
String pkgname = null, name = null;
String name = null;
try {
BufferedReader bin = new BufferedReader(new FileReader(source));
String line;
while ((line = bin.readLine()) != null) {
Matcher pm = PACKAGE_PATTERN.matcher(line);
if (pm.find()) {
pkgname = pm.group(1);
}
Matcher nm = NAME_PATTERN.matcher(line);
if (nm.find()) {
name = nm.group(1);
break;
}
}
bin.close();
// make sure we found something
if (name == null) {
System.err.println(
"Unable to locate interface name in " + source + ".");
return;
}
// prepend the package name to get a name we can Class.forName()
if (pkgname != null) {
name = pkgname + "." + name;
}
name = GenUtil.readClassName(source);
} catch (Exception e) {
System.err.println(
"Failed to parse " + source + ": " + e.getMessage());
@@ -361,18 +300,6 @@ public abstract class InvocationTask extends Task
}
}
protected static String simpleName (Class clazz)
{
if (clazz.isArray()) {
return simpleName(clazz.getComponentType()) + "[]";
} else {
Package pkg = clazz.getPackage();
int offset = (pkg == null) ? 0 : pkg.getName().length()+1;
String name = clazz.getName().substring(offset);
return StringUtil.replace(name, "$", ".");
}
}
protected static String importify (String name)
{
int didx = name.indexOf("$");
@@ -394,12 +321,4 @@ public abstract class InvocationTask extends Task
/** {@link InvocationListener} resolved with the proper classloader so
* that we can compare it to loaded derived classes. */
protected Class _ilistener;
/** A regular expression for matching the package declaration. */
protected static final Pattern PACKAGE_PATTERN =
Pattern.compile("^\\s*package\\s+(\\S+)\\W");
/** A regular expression for matching the interface declaration. */
protected static final Pattern NAME_PATTERN =
Pattern.compile("^\\s*public\\s+interface\\s+(\\S+)(\\W|$)");
}
@@ -0,0 +1,34 @@
/**
* Requests that the <code>$field</code> field be set to the
* specified value. The local value will be updated immediately and an
* event will be propagated through the system to notify all listeners
* that the attribute did change. Proxied copies of this object (on
* clients) will apply the value change when they received the
* attribute changed notification.
*/
public void set$upfield ($type value)
{
$type ovalue = this.$field;
requestAttributeChange(
$capfield, $wrapfield, $wrapofield);
this.$field = value;
}
#if ($elemtype)
/**
* Requests that the <code>index</code>th element of
* <code>$field</code> field be set to the specified value.
* The local value will be updated immediately and an event will be
* propagated through the system to notify all listeners that the
* attribute did change. Proxied copies of this object (on clients)
* will apply the value change when they received the attribute
* changed notification.
*/
public void set${upfield}At ($elemtype value, int index)
{
$elemtype ovalue = this.$field[index];
requestElementUpdate(
$capfield, index, $wrapelem, $wrapoelem);
this.$field[index] = value;
}
#end
@@ -0,0 +1,2 @@
/** The field name of the <code>$field</code> field. */
public static final String $capfield = "$field";
@@ -0,0 +1,19 @@
/**
* Requests that <code>oid</code> be added to the <code>$field</code>
* oid list. The list will not change until the event is actually
* propagated through the system.
*/
public void addTo$upfield (int oid)
{
requestOidAdd($capfield, oid);
}
/**
* Requests that <code>oid</code> be removed from the
* <code>$field</code> oid list. The list will not change until the
* event is actually propagated through the system.
*/
public void removeFrom$upfield (int oid)
{
requestOidRemove($capfield, oid);
}
@@ -0,0 +1,45 @@
/**
* Requests that the specified entry be added to the
* <code>$field</code> set. The set will not change until the event is
* actually propagated through the system.
*/
public void addTo$upfield (DSet.Entry elem)
{
requestEntryAdd($capfield, $field, elem);
}
/**
* Requests that the entry matching the supplied key be removed from
* the <code>$field</code> set. The set will not change until the
* event is actually propagated through the system.
*/
public void removeFrom$upfield (Comparable key)
{
requestEntryRemove($capfield, $field, key);
}
/**
* Requests that the specified entry be updated in the
* <code>$field</code> set. The set will not change until the event is
* actually propagated through the system.
*/
public void update$upfield (DSet.Entry elem)
{
requestEntryUpdate($capfield, $field, elem);
}
/**
* Requests that the <code>$field</code> field be set to the
* specified value. Generally one only adds, updates and removes
* entries of a distributed set, but certain situations call for a
* complete replacement of the set value. The local value will be
* updated immediately and an event will be propagated through the
* system to notify all listeners that the attribute did
* change. Proxied copies of this object (on clients) will apply the
* value change when they received the attribute changed notification.
*/
public void set$upfield ($type $field)
{
requestAttributeChange($capfield, $field, this.$field);
this.$field = $field;
}