589 lines
22 KiB
Java
589 lines
22 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* javax.baja.nre.util.TextUtil
|
|
* javax.baja.sys.Action
|
|
* javax.baja.sys.BAction
|
|
* javax.baja.sys.BBoolean
|
|
* javax.baja.sys.BComplex
|
|
* javax.baja.sys.BDouble
|
|
* javax.baja.sys.BFloat
|
|
* javax.baja.sys.BInteger
|
|
* javax.baja.sys.BLink
|
|
* javax.baja.sys.BLong
|
|
* javax.baja.sys.BString
|
|
* javax.baja.sys.BTopic
|
|
* javax.baja.sys.BValue
|
|
* javax.baja.sys.BajaRuntimeException
|
|
* javax.baja.sys.Flags
|
|
* javax.baja.sys.Property
|
|
* javax.baja.sys.Slot
|
|
* javax.baja.sys.SlotCursor
|
|
* javax.baja.util.BWsAnnotation
|
|
* org.apache.oro.text.perl.Perl5Util
|
|
*/
|
|
package com.tridium.program.module;
|
|
|
|
import com.tridium.program.BProgram;
|
|
import com.tridium.program.module.BProgramModule;
|
|
import com.tridium.program.module.BuildException;
|
|
import java.io.BufferedReader;
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.io.StringReader;
|
|
import java.io.Writer;
|
|
import java.util.HashSet;
|
|
import javax.baja.nre.util.TextUtil;
|
|
import javax.baja.sys.Action;
|
|
import javax.baja.sys.BAction;
|
|
import javax.baja.sys.BBoolean;
|
|
import javax.baja.sys.BComplex;
|
|
import javax.baja.sys.BDouble;
|
|
import javax.baja.sys.BFloat;
|
|
import javax.baja.sys.BInteger;
|
|
import javax.baja.sys.BLink;
|
|
import javax.baja.sys.BLong;
|
|
import javax.baja.sys.BString;
|
|
import javax.baja.sys.BTopic;
|
|
import javax.baja.sys.BValue;
|
|
import javax.baja.sys.BajaRuntimeException;
|
|
import javax.baja.sys.Flags;
|
|
import javax.baja.sys.Property;
|
|
import javax.baja.sys.Slot;
|
|
import javax.baja.sys.SlotCursor;
|
|
import javax.baja.util.BWsAnnotation;
|
|
import org.apache.oro.text.perl.Perl5Util;
|
|
|
|
/*
|
|
* Illegal identifiers - consider using --renameillegalidents true
|
|
*/
|
|
public class ComponentWriter
|
|
extends PrintWriter {
|
|
private static final int tabWidth = 2;
|
|
private String[] predefinedImports;
|
|
private BProgram program;
|
|
private Class programClass;
|
|
private String packageName;
|
|
private String compName;
|
|
static /* synthetic */ Class class$java$lang$String;
|
|
|
|
private final void init(BProgram bProgram, String string) {
|
|
this.program = bProgram;
|
|
try {
|
|
this.programClass = bProgram.getCode().newInstance().getClass();
|
|
}
|
|
catch (Exception exception) {
|
|
exception.printStackTrace();
|
|
throw new BajaRuntimeException((Throwable)exception);
|
|
}
|
|
this.packageName = string;
|
|
this.compName = BProgramModule.toComponentName(bProgram);
|
|
}
|
|
|
|
public void generate() {
|
|
this.writeHeader();
|
|
this.writeImports();
|
|
this.writeClass();
|
|
this.flush();
|
|
this.close();
|
|
}
|
|
|
|
protected void writeHeader() {
|
|
this.wl("/* Auto-generated by the Program Module-Builder. */");
|
|
this.w("package ").w(this.packageName).wl(";");
|
|
this.nl();
|
|
}
|
|
|
|
protected void writeImports() {
|
|
Object object;
|
|
HashSet<String> hashSet = new HashSet<String>();
|
|
int n = 0;
|
|
while (n < this.predefinedImports.length) {
|
|
hashSet.add(this.predefinedImports[n]);
|
|
++n;
|
|
}
|
|
String string = this.program.getCode().getUserDefinedImports();
|
|
String[] stringArray = TextUtil.split((String)string, (char)';');
|
|
int n2 = 0;
|
|
while (n2 < stringArray.length) {
|
|
hashSet.add(TextUtil.split((String)stringArray[n2], (char)':')[1] + ".*;");
|
|
++n2;
|
|
}
|
|
SlotCursor slotCursor = this.program.getProperties();
|
|
while (slotCursor.next()) {
|
|
if (!slotCursor.property().isDynamic()) continue;
|
|
object = slotCursor.get().getClass();
|
|
hashSet.add(TextUtil.getPackageName((Class)object) + ".*;");
|
|
}
|
|
object = hashSet.toArray(new String[hashSet.size()]);
|
|
int n3 = 0;
|
|
while (n3 < ((String[])object).length) {
|
|
this.w("import ").wl(object[n3]);
|
|
++n3;
|
|
}
|
|
this.nl();
|
|
}
|
|
|
|
protected void writeClass() {
|
|
this.w("public class ").wl(this.compName);
|
|
this.tab().wl("extends BComponent implements Runnable");
|
|
this.wl("{");
|
|
this.writeProperties();
|
|
this.writeActions();
|
|
this.writeBComponentOverrides();
|
|
this.writeRunnable();
|
|
this.writeAccess();
|
|
this.writeUtils();
|
|
this.writeStubs();
|
|
this.writeCode();
|
|
this.writeType();
|
|
this.wl("}");
|
|
}
|
|
|
|
protected void writeType() {
|
|
this.section("Type");
|
|
this.tab().wl("public Type getType() { return TYPE; }");
|
|
this.tab().w("public static final Type TYPE = Sys.loadType(").w(this.compName).w(".class);");
|
|
this.nl().nl();
|
|
}
|
|
|
|
protected void writeProperties() {
|
|
SlotCursor slotCursor = this.program.getProperties();
|
|
while (slotCursor.next()) {
|
|
BValue bValue;
|
|
Property property = slotCursor.property();
|
|
if (property.isFrozen() || (bValue = slotCursor.get().asValue()) instanceof BWsAnnotation || bValue instanceof BLink || bValue instanceof BAction || bValue instanceof BTopic) continue;
|
|
if (bValue instanceof BDouble || bValue instanceof BLong) {
|
|
throw new BuildException("Property slot type not supported: " + bValue.getType());
|
|
}
|
|
this.section("Property \"" + property.getName() + '\"');
|
|
this.writeNewProperty(property, bValue.isSimple());
|
|
this.writeGetSet(property);
|
|
}
|
|
}
|
|
|
|
protected final void writeNewProperty(Property property, boolean bl) {
|
|
String string = "B" + property.getType().getTypeName();
|
|
String string2 = bl ? "(BValue)" + string + ".TYPE.getInstance()" : "new " + string + "()";
|
|
this.tab().w("public static final Property ").w(property.getName()).w(" = newProperty(").w(this.flags((Slot)property)).w(", ").w(string2).w(", ").w(this.facets((Slot)property)).w(");").nl().nl();
|
|
}
|
|
|
|
protected final void writeGetSet(Property property) {
|
|
CompProperty compProperty = new CompProperty(property);
|
|
this.tab().w("public ").w(compProperty.type).w(" ").w(compProperty.getter()).w("() ").w("{ return ").w(compProperty.cast).w("get" + compProperty.postfix).w("(" + compProperty.name() + "); }").nl().nl();
|
|
this.tab().w("public void ").w(compProperty.setter()).w("(" + compProperty.type + " v)").w(" { set" + compProperty.postfix + '(' + compProperty.name() + ", v, null); }").nl().nl();
|
|
}
|
|
|
|
protected void writeActions() {
|
|
SlotCursor slotCursor = this.program.getActions();
|
|
while (slotCursor.next()) {
|
|
Action action = slotCursor.action();
|
|
CompAction compAction = new CompAction(slotCursor.action());
|
|
if (action.isFrozen() && !compAction.name().equals("execute")) continue;
|
|
this.section("Action \"" + compAction.name() + '\"');
|
|
this.tab().w("public static final Action ").w(compAction.name()).w(" = newAction(").w(this.flags((Slot)action)).w(", ").w(compAction.paramDefault()).w(", ").w(this.facets((Slot)action)).w(");").nl().nl();
|
|
this.writeActionInvoke(action);
|
|
this.writeActionDelegate(action);
|
|
}
|
|
}
|
|
|
|
protected void writeActionInvoke(Action action) {
|
|
CompAction compAction = new CompAction(action);
|
|
StringBuffer stringBuffer = new StringBuffer().append("public ").append(compAction.returnType()).append(" ").append(compAction.name()).append("(").append(compAction.parameter()).append(")").append("{ ").append(compAction.returnStmt()).append("invoke(").append(compAction.name()).append(", ").append(compAction.invokeParam()).append(", null); }");
|
|
this.tab().wl(stringBuffer.toString()).nl();
|
|
}
|
|
|
|
protected void writeActionDelegate(Action action) {
|
|
CompAction compAction = new CompAction(action);
|
|
this.tab().wl("/** Autogenerated delegate for \"" + compAction.getOn() + "\" */");
|
|
this.tab().w("public ").w(compAction.returnType()).w(" " + compAction.getDo()).w("(" + compAction.parameter() + ") throws Exception").nl().tab().wl("{").tab(2).w("try { ").w(compAction.returnStmt()).w(compAction.getOn()).w("(" + compAction.actualParam() + "); }").nl().tab(2).w("catch (Throwable t) { throw new Exception(t); }").nl().tab().wl("}").nl();
|
|
}
|
|
|
|
protected void writeBComponentOverrides() {
|
|
this.section("BComponent Overrides");
|
|
this.tab().wl("public void started() throws Exception { try { onStart(); } catch(Throwable t) { throw new Exception(t); } }").nl();
|
|
this.tab().wl("public void stopped() throws Exception { try { onStop(); } catch(Throwable t) { throw new Exception(t); } }").nl();
|
|
this.writeChanged();
|
|
}
|
|
|
|
protected void writeChanged() {
|
|
this.tab(1).wl("public void changed(Property prop, Context cx)").tab(1).wl("{").tab(2).wl("super.changed(prop, cx);").tab(2).wl("if (!isRunning()) return;").tab(2).wl("if (Flags.isExecuteOnChange(this, prop)) execute();").tab(1).wl("}").nl();
|
|
}
|
|
|
|
protected final void writeRunnable() {
|
|
if (!this.programDeclares("run", null)) {
|
|
this.section("Runnable");
|
|
this.tab().wl("public void run() { System.out.println(\"Source BProgram did not override run(). Exiting thread.\"); }").nl();
|
|
}
|
|
}
|
|
|
|
protected final void writeAccess() {
|
|
this.section("Access");
|
|
this.tab().wl("public final BComponent getComponent() { return this; }").nl();
|
|
this.tab().wl("public final BComponent getProgram() { return this; }").nl();
|
|
}
|
|
|
|
protected final void writeUtils() {
|
|
String string = this.program.getCode().getSource();
|
|
this.section("Utils");
|
|
Class[] classArray = new Class[1];
|
|
Class clazz = class$java$lang$String;
|
|
if (clazz == null) {
|
|
clazz = classArray[0] = (class$java$lang$String = ComponentWriter.class("[Ljava.lang.String;", false));
|
|
}
|
|
if (!this.programDeclares("print", classArray)) {
|
|
this.tab().wl("/** Print a string to standard out without a trailing new-line. */");
|
|
this.tab().wl("public void print(String s) { System.out.print(s); System.out.flush(); }").nl();
|
|
} else {
|
|
this.tab().wl("// print(String s) is overridden by program source.").nl();
|
|
}
|
|
Class[] classArray2 = new Class[1];
|
|
Class clazz2 = class$java$lang$String;
|
|
if (clazz2 == null) {
|
|
clazz2 = classArray2[0] = (class$java$lang$String = ComponentWriter.class("[Ljava.lang.String;", false));
|
|
}
|
|
if (!this.programDeclares("println", classArray2)) {
|
|
this.tab().wl("/** Print a string to standard out with a trailing new-line. */");
|
|
this.tab().wl("public void println(String s) { System.out.println(s); }").nl();
|
|
} else {
|
|
this.tab().wl("// println(String s) is overridden by program souce.").nl();
|
|
}
|
|
}
|
|
|
|
protected final void writeStubs() {
|
|
String string = this.program.getCode().getSource();
|
|
this.section("ProgramBase Stubs");
|
|
if (!this.programDeclares("onStart", null)) {
|
|
this.tab().wl("public void onStart() throws Throwable {}").nl();
|
|
}
|
|
if (!this.programDeclares("onStop", null)) {
|
|
this.tab().wl("public void onStop() throws Throwable {}").nl();
|
|
}
|
|
if (!this.programDeclares("onExecute", null)) {
|
|
this.tab().wl("public void onExecute() throws Throwable {}").nl();
|
|
}
|
|
}
|
|
|
|
protected void writeCode() {
|
|
Perl5Util perl5Util = new Perl5Util();
|
|
String string = this.program.getCode().getSource();
|
|
StringBuffer stringBuffer = new StringBuffer();
|
|
string = perl5Util.substitute("s/BProgram\\./" + this.compName + "./g", string);
|
|
this.section("BProgram Source Code");
|
|
this.writeSourceLines(string);
|
|
}
|
|
|
|
protected boolean programDeclares(String string, Class[] classArray) {
|
|
try {
|
|
this.programClass.getDeclaredMethod(string, classArray);
|
|
return true;
|
|
}
|
|
catch (NoSuchMethodException noSuchMethodException) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected final void writeSourceLines(String string) {
|
|
try {
|
|
String string2;
|
|
BufferedReader bufferedReader = new BufferedReader(new StringReader(string));
|
|
while ((string2 = bufferedReader.readLine()) != null) {
|
|
this.tab().wl(string2);
|
|
}
|
|
this.nl();
|
|
}
|
|
catch (IOException iOException) {
|
|
throw new IllegalStateException();
|
|
}
|
|
}
|
|
|
|
protected void section(String string) {
|
|
this.nl();
|
|
this.wl("////////////////////////////////////////////////////////////////");
|
|
this.wl("// " + string);
|
|
this.wl("////////////////////////////////////////////////////////////////");
|
|
this.nl();
|
|
}
|
|
|
|
protected final String flags(Slot slot) {
|
|
StringBuffer stringBuffer = new StringBuffer("0");
|
|
if (Flags.isAsync((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.ASYNC");
|
|
}
|
|
if (Flags.isComposite((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.COMPOSITE");
|
|
}
|
|
if (Flags.isConfirmRequired((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.CONFIRM_REQUIRED");
|
|
}
|
|
if (Flags.isDefaultOnClone((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.DEFAULT_ON_CLONE");
|
|
}
|
|
if (Flags.isExecuteOnChange((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.EXECUTE_ON_CHANGE");
|
|
}
|
|
if (Flags.isFanIn((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.FAN_IN");
|
|
}
|
|
if (Flags.isHidden((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.HIDDEN");
|
|
}
|
|
if (Flags.isNoAudit((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.NO_AUDIT");
|
|
}
|
|
if (Flags.isNoRun((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.NO_RUN");
|
|
}
|
|
if (Flags.isOperator((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.OPERATOR");
|
|
}
|
|
if (Flags.isReadonly((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.READONLY");
|
|
}
|
|
if (Flags.isSummary((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.SUMMARY");
|
|
}
|
|
if (Flags.isTransient((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.TRANSIENT");
|
|
}
|
|
if (Flags.isUserDefined1((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.USER_DEFINED_1");
|
|
}
|
|
if (Flags.isUserDefined2((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.USER_DEFINED_2");
|
|
}
|
|
if (Flags.isUserDefined3((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.USER_DEFINED_3");
|
|
}
|
|
if (Flags.isUserDefined4((BComplex)this.program, (Slot)slot)) {
|
|
stringBuffer.append("|Flags.USER_DEFINED_4");
|
|
}
|
|
return stringBuffer.toString();
|
|
}
|
|
|
|
protected final String facets(Slot slot) {
|
|
try {
|
|
return slot.getFacets().isNull() ? "null" : "BFacets.tryMake(\"" + slot.getFacets().encodeToString() + "\")";
|
|
}
|
|
catch (Exception exception) {
|
|
throw new BuildException("Failed to create facets. ", exception);
|
|
}
|
|
}
|
|
|
|
protected ComponentWriter w(String string) {
|
|
this.print(string);
|
|
return this;
|
|
}
|
|
|
|
protected ComponentWriter wl(String string) {
|
|
this.print(string);
|
|
this.print('\n');
|
|
return this;
|
|
}
|
|
|
|
protected ComponentWriter nl() {
|
|
this.print('\n');
|
|
return this;
|
|
}
|
|
|
|
protected ComponentWriter tab() {
|
|
return this.tab(1);
|
|
}
|
|
|
|
protected ComponentWriter tab(int n) {
|
|
return this.w(TextUtil.getSpaces((int)(n * 2)));
|
|
}
|
|
|
|
protected ComponentWriter sp(int n) {
|
|
return this.w(TextUtil.getSpaces((int)n));
|
|
}
|
|
|
|
static /* synthetic */ Class class(String string, boolean bl) {
|
|
try {
|
|
Class<?> clazz = Class.forName(string);
|
|
if (!bl) {
|
|
clazz = clazz.getComponentType();
|
|
}
|
|
return clazz;
|
|
}
|
|
catch (ClassNotFoundException classNotFoundException) {
|
|
throw new NoClassDefFoundError(classNotFoundException.getMessage());
|
|
}
|
|
}
|
|
|
|
private final /* synthetic */ void this() {
|
|
this.predefinedImports = new String[]{"java.util.*;", "javax.baja.sys.*;", "javax.baja.status.*;", "javax.baja.util.*;", "javax.baja.security.*;"};
|
|
}
|
|
|
|
public ComponentWriter(Writer writer, BProgram bProgram, String string) {
|
|
super(writer);
|
|
this.this();
|
|
this.init(bProgram, string);
|
|
}
|
|
|
|
/*
|
|
* Illegal identifiers - consider using --renameillegalidents true
|
|
*/
|
|
public static class CompProperty {
|
|
public Property prop;
|
|
String cast;
|
|
String postfix;
|
|
String type;
|
|
String bname;
|
|
Class[] setParams;
|
|
static /* synthetic */ Class class$java$lang$String;
|
|
|
|
public String name() {
|
|
return this.prop.getName();
|
|
}
|
|
|
|
public String getter() {
|
|
return "get" + TextUtil.capitalize((String)this.name());
|
|
}
|
|
|
|
public String setter() {
|
|
return "set" + TextUtil.capitalize((String)this.name());
|
|
}
|
|
|
|
public String cast() {
|
|
return this.cast;
|
|
}
|
|
|
|
public String postfix() {
|
|
return this.postfix;
|
|
}
|
|
|
|
public String type() {
|
|
return this.type;
|
|
}
|
|
|
|
public String typeName() {
|
|
return this.bname;
|
|
}
|
|
|
|
static /* synthetic */ Class class(String string, boolean bl) {
|
|
try {
|
|
Class<?> clazz = Class.forName(string);
|
|
if (!bl) {
|
|
clazz = clazz.getComponentType();
|
|
}
|
|
return clazz;
|
|
}
|
|
catch (ClassNotFoundException classNotFoundException) {
|
|
throw new NoClassDefFoundError(classNotFoundException.getMessage());
|
|
}
|
|
}
|
|
|
|
private final /* synthetic */ void this() {
|
|
this.cast = "";
|
|
this.postfix = "";
|
|
}
|
|
|
|
public CompProperty(Property property) {
|
|
this.this();
|
|
this.prop = property;
|
|
BValue bValue = property.getDefaultValue();
|
|
this.type = this.bname = "B" + bValue.getType().getTypeName();
|
|
if (bValue.isSimple()) {
|
|
if (bValue instanceof BString) {
|
|
this.postfix = "String";
|
|
this.type = "String";
|
|
Class[] classArray = new Class[1];
|
|
Class clazz = class$java$lang$String;
|
|
if (clazz == null) {
|
|
clazz = class$java$lang$String = CompProperty.class("[Ljava.lang.String;", false);
|
|
}
|
|
classArray[0] = clazz;
|
|
this.setParams = classArray;
|
|
} else if (bValue instanceof BBoolean) {
|
|
this.type = "boolean";
|
|
this.postfix = "Boolean";
|
|
this.setParams = new Class[]{Boolean.TYPE};
|
|
} else if (bValue instanceof BInteger) {
|
|
this.type = "int";
|
|
this.postfix = "Int";
|
|
this.setParams = new Class[]{Integer.TYPE};
|
|
} else if (bValue instanceof BFloat) {
|
|
this.type = "float";
|
|
this.postfix = "Float";
|
|
this.setParams = new Class[]{Float.TYPE};
|
|
} else {
|
|
this.cast = "(" + this.type + ')';
|
|
this.setParams = new Class[]{bValue.getClass()};
|
|
}
|
|
} else if (bValue.isValue()) {
|
|
this.cast = "(" + this.type + ')';
|
|
this.setParams = new Class[]{bValue.getClass()};
|
|
} else {
|
|
throw new IllegalStateException(this.bname + ", " + bValue.getType());
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class CompAction {
|
|
public static final String ACTUAL_PARAM_VAR = "v";
|
|
public Action action;
|
|
|
|
public String name() {
|
|
return this.action.getName();
|
|
}
|
|
|
|
public String returnType() {
|
|
return this.action.getReturnType() == null ? "void" : "B" + this.action.getReturnType().getTypeName();
|
|
}
|
|
|
|
public String parameter() {
|
|
return this.action.getParameterDefault() == null ? "" : this.paramType() + " v";
|
|
}
|
|
|
|
public String paramType() {
|
|
return this.action.getParameterType() == null ? null : "B" + this.action.getParameterType().getTypeName();
|
|
}
|
|
|
|
public Class[] paramTypeArray() {
|
|
if (this.action.getParameterType() == null) {
|
|
return null;
|
|
}
|
|
return new Class[]{this.action.getParameterType().getInstance().getClass()};
|
|
}
|
|
|
|
public String paramDefault() {
|
|
BValue bValue = this.action.getParameterDefault();
|
|
if (bValue == null) {
|
|
return "null";
|
|
}
|
|
String string = this.paramType();
|
|
if (bValue.isSimple()) {
|
|
return "(BValue)" + string + ".TYPE.getInstance()";
|
|
}
|
|
return "new " + string + "()";
|
|
}
|
|
|
|
public String returnStmt() {
|
|
return this.action.getReturnType() == null ? "" : "return (" + this.returnType() + ')';
|
|
}
|
|
|
|
public String invokeParam() {
|
|
return this.paramType() == null ? "null" : ACTUAL_PARAM_VAR;
|
|
}
|
|
|
|
public String actualParam() {
|
|
return this.action.getParameterType() == null ? "" : ACTUAL_PARAM_VAR;
|
|
}
|
|
|
|
public String getDo() {
|
|
return "do" + TextUtil.capitalize((String)this.name());
|
|
}
|
|
|
|
public String getOn() {
|
|
return "on" + TextUtil.capitalize((String)this.name());
|
|
}
|
|
|
|
public CompAction(Action action) {
|
|
this.action = action;
|
|
}
|
|
}
|
|
}
|
|
|