From 98bb871e6d8a154dc5855d33d0c3ee53d0778d08 Mon Sep 17 00:00:00 2001 From: Jamie Doornbos Date: Thu, 8 May 2008 19:06:32 +0000 Subject: [PATCH] Fixed code generation for existing msoy services * Created concept of a pattern for transforming imports rather than have some methods assume a suffix is provided and others assume a prefix * Leave full array types in import set initially so that they can be dealt with differently by different code exporters * Added more primitive types and array types for action script marshallers, including conversion to TypedArray * Add listener marshaller mungings for action script marshallers' imports * Added handling for array imports for action script services git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5048 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../presents/tools/GenServiceTask.java | 51 ++++++- .../threerings/presents/tools/ImportSet.java | 125 ++++++++++++++++-- .../presents/tools/InvocationTask.java | 2 +- 3 files changed, 166 insertions(+), 12 deletions(-) diff --git a/src/java/com/threerings/presents/tools/GenServiceTask.java b/src/java/com/threerings/presents/tools/GenServiceTask.java index a89cf0d36..62439aa36 100644 --- a/src/java/com/threerings/presents/tools/GenServiceTask.java +++ b/src/java/com/threerings/presents/tools/GenServiceTask.java @@ -46,6 +46,12 @@ import com.threerings.presents.server.InvocationProvider; /** * An Ant task for generating invocation service marshalling and * unmarshalling classes. + * TODO: when generating the imports for exported action script files, there are just enough + * conversions of primitive types (e.g. float -> Number), array types (e.g. int[] -> TypedArray) + * and three rings utility types (e.g. float -> Float) to make the existing serivces work. It + * should be possible to create a complete list of these conversions so that future services + * can be generated without problems. + * TODO: when generating imports, remove imports of classes in the same pacakge. */ public class GenServiceTask extends InvocationTask { @@ -179,8 +185,11 @@ public class GenServiceTask extends InvocationTask // get rid of java.lang stuff and primitives imports.removeGlobals(); + // get rid of all arrays (they are automatic in java) + imports.removeArrays(); + // for each listener type, also import the corresponding marshaller - imports.duplicateAndMunge("Listener", + imports.duplicateAndMunge("*Listener", "Service", "Marshaller", "Listener", "Marshaller", ".client.", ".data."); @@ -233,16 +242,34 @@ public class GenServiceTask extends InvocationTask imports.replace("byte", "com.threerings.util.Byte"); imports.replace("int", "com.threerings.util.Integer"); imports.replace("boolean", "com.threerings.util.langBoolean"); - + imports.replace("[B", "flash.utils.ByteArray"); + imports.replace("float", "com.threerings.util.Float"); + imports.replace("[I", "com.threerings.io.TypedArray"); + // ye olde special case - any method that uses a default listener // causes the need for the default listener marshaller - imports.duplicateAndMunge("InvocationService_InvocationListener", + imports.duplicateAndMunge("*.InvocationService_InvocationListener", "InvocationService_InvocationListener", "InvocationMarshaller_ListenerMarshaller", ".client.", ".data."); + // any use of a listener requires the listener marshaller + imports.pushOut("*.InvocationService_InvocationListener"); + imports.duplicateAndMunge("*Listener", + "Service", "Marshaller", + "Listener", "Marshaller", + ".client.", ".data."); + imports.popIn(); + // get rid of java.lang stuff and any remaining primitives imports.removeGlobals(); + + if (imports.removeAll("[L*") > 0) { + imports.add("com.threerings.io.TypedArray"); + } + + // get rid of remaining arrays + imports.removeArrays(); ctx.put("imports", imports.toList()); @@ -312,9 +339,21 @@ public class GenServiceTask extends InvocationTask imports.add(Client.class); imports.add(InvocationService.class); + // allow primitive types in service methods + // TODO: are more primitive types needed? + imports.replace("[B", "flash.utils.ByteArray"); + imports.replace("[I", "com.threerings.io.TypedArray"); + + if (imports.removeAll("[L*") > 0) { + imports.add("com.threerings.io.TypedArray"); + } + // get rid of primitives and java.lang classes imports.removeGlobals(); + // get rid of remaining arrays + imports.removeArrays(); + // change imports of Foo$Bar to Foo_Bar imports.translateInnerClasses(); @@ -405,6 +444,9 @@ public class GenServiceTask extends InvocationTask // get rid of primitives and java.lang types imports.removeGlobals(); + + // get rid of arrays + imports.removeArrays(); // import the Marshaller corresponding to the service imports.addMunged(sdesc.service, @@ -465,6 +507,9 @@ public class GenServiceTask extends InvocationTask // get rid of primitives and java.lang types imports.removeGlobals(); + // get rid of arrays + imports.removeArrays(); + // import Foo instead of Foo$Bar imports.swapInnerClassesForParents(); diff --git a/src/java/com/threerings/presents/tools/ImportSet.java b/src/java/com/threerings/presents/tools/ImportSet.java index 72dfa56bb..1ef6a4038 100644 --- a/src/java/com/threerings/presents/tools/ImportSet.java +++ b/src/java/com/threerings/presents/tools/ImportSet.java @@ -1,8 +1,10 @@ package com.threerings.presents.tools; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.regex.Pattern; import com.samskivert.util.ComparableArrayList; import com.samskivert.util.StringUtil; @@ -15,6 +17,12 @@ import com.samskivert.util.StringUtil; * convenience for easily specifying multiple find/replace pairs. For example, to replace "Foo" * with "Bar" and "123" with "ABC", a function can be called with the 4 arguments "Foo", "Bar", * "123", "ABC" for the String... replace argument. + * + *

A few methods also use a "pattern" string parameter that is used to match a class name. + * This is a dumbed down regular expression (to avoid many \.) where "*" means .* and no other + * characters have special meaning. The pattern is also implicitly enclosed with ^$ so that the + * pattern must match the class name in its entirity. Callers will mostly use this to specify a + * prefix like "something*" or a suffix like "*something". */ public class ImportSet { @@ -33,7 +41,9 @@ public class ImportSet */ public void add (String name) { - _imports.add(name); + if (name != null) { + _imports.add(name); + } } /** @@ -87,6 +97,14 @@ public class ImportSet } } + /** + * Gets rid of array imports. + */ + public int removeArrays () + { + return removeAll("[*"); + } + /** * Replaces inner class imports (those with a '$') with an import of the parent class. */ @@ -126,6 +144,40 @@ public class ImportSet addAll(inner); } + /** + * Temporarily remove one import matching the given pattern. The most recently pushed pattern + * can be re-added using popIn. If there is no match, a null value is pushed so + * that popIn can still be called. + * @param pattern to match + */ + public void pushOut (String pattern) + { + Pattern pat = makePattern(pattern); + Iterator i = _imports.iterator(); + while (i.hasNext()) { + String imp = i.next(); + if (pat.matcher(imp).matches()) { + i.remove(); + _pushed.add(imp); + return; + } + } + _pushed.add(null); + } + + /** + * Re-adds the most recently popped import to the set. If a null value was pushed, does + * nothing. + * @throws IndexOutOfBoundsException if there is nothing to pop + */ + public void popIn () + { + String front = _pushed.remove(_pushed.size() - 1); + if (front != null) { + _imports.add(front); + } + } + /** * Removes the name of a class from the imports. * @param clazz the class whose name should be removed @@ -136,7 +188,7 @@ public class ImportSet } /** - * Replaces any import exactly matching the 0th argument with the 1st argument and so on. + * Replaces any import exactly each find string with the corresponding replace string. * See the description above. * @param replace array of pairs for search/replace */ @@ -156,18 +208,40 @@ public class ImportSet } _imports.addAll(toAdd); } + + /** + * Remove all imports matching the given pattern. + * @param pattern the dumbed down regex to match (see description above) + * @return the number of imports removed + */ + public int removeAll (String pattern) + { + Pattern pat = makePattern(pattern); + int removed = 0; + Iterator i = _imports.iterator(); + while (i.hasNext()) { + String name = i.next(); + if (pat.matcher(name).matches()) { + i.remove(); + ++removed; + } + } + return removed; + } /** - * Adds a new munged import for each existing import that matches a suffix. The new entry is - * a copy of the old entry but modified according to the "replace" pattern described above. - * @param suffix to filter the search for imports to duplicate - * @param replace array of string pairs to search/replace on the duplicated import + * Adds a new munged import for each existing import that matches a pattern. The new entry is + * a copy of the old entry but modified according to the given find/replace pairs (see + * description above). + * @param pattern to qualify imports to duplicate + * @param replace pairs to find/replace on the new import */ - public void duplicateAndMunge (String suffix, String... replace) + public void duplicateAndMunge (String pattern, String... replace) { + Pattern pat = makePattern(pattern); HashSet toMunge = new HashSet(); for (String name : _imports) { - if (name.endsWith(suffix)) { + if (pat.matcher(name).matches()) { toMunge.add(name); } } @@ -198,5 +272,40 @@ public class ImportSet return StringUtil.toString(_imports); } + /** + * Create a real regular expression from the dumbed down input. + * @param input the dumbed down wildcard expression + * @return the calculated regular expression + */ + protected static Pattern makePattern (String input) + { + StringBuilder pattern = new StringBuilder(); + pattern.append("^"); + + while (true) + { + String[] parts = _splitter.split(input, 2); + pattern.append(Pattern.quote(parts[0])); + if (parts.length == 1) { + break; + } + int length = parts[0].length(); + String wildcard = input.substring(length, length + 1); + if (wildcard.equals("*")) { + pattern.append(".*"); + } + else { + System.err.println("Bad wildcard " + wildcard); + } + input = parts[1]; + } + + pattern.append("$"); + return Pattern.compile(pattern.toString()); + } + protected HashSet _imports = new HashSet(); + protected List _pushed = new ArrayList(); + + protected static Pattern _splitter = Pattern.compile("\\*"); } diff --git a/src/java/com/threerings/presents/tools/InvocationTask.java b/src/java/com/threerings/presents/tools/InvocationTask.java index 28e6d76cc..d3bc0776c 100644 --- a/src/java/com/threerings/presents/tools/InvocationTask.java +++ b/src/java/com/threerings/presents/tools/InvocationTask.java @@ -123,7 +123,7 @@ public abstract class InvocationTask extends Task listenerArgs.add(new ListenerArgument(ii, arg)); } - imports.add(arg); + imports.add(args[ii]); } }