The SmartFrog Language
The SmartFrog Language is a simple text-based, name-value pair language. What differentiates it from XML or JSON is its use of references to eliminate duplication across parts of a configuration.
Files
SmartFrog files are ASCII text files with the extension .sf. All files that are to be included in other files through #include instructions must be on the classpath of the client-side process initiating the deployment. When deploying with full security enabled, every .sf file must be in a JAR signed by an entity that the local SmartFrog runtime trusts.
Include files
SmartFrog files can be included through the #include instruction, which locates the named .sf file on the classpath, and includes it.
system extends Compound {
#include "/org/smartfrog/services/files/foo.sf"
}
- Include files are resources on the classpath of the deploying JVM; they are expanded at parse time ---before the components are deployed.
- Relative paths are not supported.
- If you nest a #include instruction inside a component declaration (as done above), then all components declared in the included file are appropriately nested, except for those references that are made relative to ROOT
Comments
C++/Java style comments, both single line // and multi-line /* style.
Attributes
Attributes are simple tokens, which must start with a letter, a letter which may be followed by more letters, digits or any of the characters ._-+@#~$%^&. The following are all legal attribute names
test.timeout 1000;
test-server "lucky";
test-server2 "unlucky";
listen@port 46;
user+name+unknown true;
Because - and + are reserved, it is important to place spaces between attribute names in functions, as the parser will interpret test-server++test-server2 as a reference to a single attribute of that name, and not the concatenation operation test-server ++ test-server2.
There is a special attribute name, -- which refers to an anonymous attribute. It is used to declare a list of elements in which their name is unimportant.
actions extends Compound {
-- extends Server {port 4040;}
-- extends Server {port 4041;}
-- extends Server {port 4042;}
}
This declares a component action with three children, their names to be automatically assigned at parse time. This is different from declaring named children, in which the last declaration is all that is preserved
actions extends Compound {
server extends Server {port 4040;}
server extends Server {port 4041;}
server extends Server {port 4042;}
}
This declares only one child, server with the value of server:port set to 4042.
Attribute Value types
There are a limited set of types for attributes: strings, numbers , binary data and lists
Integers
Integer numbers such as 345
timeout 47;
pause -3476839;
Internally integers map to java.lang.Integer instances; they are signed 32 bit numbers.
Long numbers
Long numbers such as 65325L
Internally long numbers map to java.lang.Long instances; they are signed 64 bit numbers.
Float numbers
Floating point numbers
timeout 47.46F;
pause -34.2e-10f;
Internally long numbers map to java.lang.Float instances; they are signed 32-bit floating point numbers.
Double numbers
Floating point numbers with more accuracy and size than simple float numbers. Floating point values default to being doubles, unless explicitly declared otherwise with an F or f suffix on the number.
timeout 47.46;
pause -34.2e-10D;
Internally long numbers map to java.lang.Double instances; they are signed 64-bit floating point numbers.
Strings.
simplestring "this is a string";
longstring #this multiline
string includes carriage returns
inline, and must
still be followed by a semicolon#;
Binary Data
binary data can be encoded in the text file in Base-64, hex, decimal, octal or binary format. Whitespace (tab, spaces and newlines are ignored in the binary data, so can be used to lay out the values better
icon #HEX#b3a400 0304FF#;
permission #OCT#377#;
bitmask #BIN#00101101#;
auth #B64#a5zuA1bc
Azu48CEh#;
Boolean values
Both boolean values, true and false may be used as attribute values
retry true;
https-only false;
Null values
The NULL keyword can be used to indicate null, as can leaving the value empty
password NULL;
backup_host;
Operators
! + - / == != >= <= < * ++ <> && ||
IF (val1 > val2) THEN (val1 - val2) ELSE (val2 - val1) FI;
Lists
v1 [1,2,3];
v2 [9,8,7];
v3 [v1, v2];
Components
Components are what the SmartFrog runtime deploys. In the language, they are simply named attribute lists.
Component::= extends [LAZY] Type Body
Type::= [ NULL | BaseReference ]
Body ::= ( ; | { AttributeList } )
The Root component called sfConfig identifies the component in a description to deploy
sfConfig extends Prim {
portNum 4047;
sfProcessHost "ahost.smartfrog.org";
administrators ["patrick",ATTRIB ROOT:sysadmin];
}
References
References are what makes the SmartFrog unique. Rather than cut and paste values across component configurations, data can be shared by reference. LAZY references are an even more advanced concept. A LAZY reference is only evaluated after deployment, when the deployed component resolves that reference. They can be used to refer to values in the deployed system.
| Reference Part |
Meaning |
| ROOT |
Reference to the base of the descriptor. When LAZY, it refers to the base of the local tree of deployed components. |
| PARENT |
Reference to the parent descriptor; When LAZY, it refers to the parent component. |
| ATTRIB WORD |
closest attribute 'WORD' |
| HERE WORD |
local attribute 'WORD' only; no resolution against parent attributes |
| THIS |
local component '.' |
| OPTIONAL(defval) |
Gives an optional value for unresolved references. References can not be used in
the default value |
| (arbitrary word not recognised as a keyword) |
ATTRIB if first/only part, else HERE |
| CONSTANT WORD/STRING |
Extracts the toString()} value of a static field from a Java class. For example, {{CONSTANT "org.example.Class1.name" would expect to find a static field name in the class org.example.Class1. When LAZY the constant is
resolved in the deployed JVM |
| ICONSTANT WORD/STRING |
Extracts the integer value of a static field from a Java class. For example, CONSTANT "org.example.Class1.count" would expect to find a static field count in the class org.example.Class1. When LAZY the constant is
resolved in the deployed JVM |
| IPROPERTY WORD |
JVM integer property in the client or (when LAZY) server VM |
| ENVPROPERTY WORD |
Environment variable in the client or (when LAZY) server VM |
| IENVPROPERTY |
Integer environment variable in the client or (when LAZY) server VM |
| PROCESS |
Current process |
| HOST WORD/STRING |
Host by reference/address |
References can be chained using the : character. Here are some example references
The path environment variable on a (possibly remote) host
remotePath HOST "192.168.2.2" : ENVPROPERTY path;
the test.timeout property, if set, otherwise 1000 milliseconds:
timeout OPTIONAL(1000) IPROPERTY test.timeout;
A LAZY reference to a logger component
logger LAZY ROOT:sfConfig:server:logger;
Functions
When a function is evaluated, its declaration is replaced by the result.
#include "org/smartfrog/functions.sf";
myString extends formatString { format "the path is $1";
-- ENVPROPERTY PATH;}
This will turn the value of myString into a string like
"the path is /usr/bin:/sbin:/bin:/usr/local/bin:/usr/java/jdk/bin"