Matthew Clemente
Cold Brews
Getting Started with Java
in Your CFML Apps
Slides Here
“A programmer drinking a cup of coffee in front of a volcano on the island of Java, oil painting”
DALL·E 2
What it's not...
It's not...
...how to write Java
It's not...
Java Upgrades
It's not...
Java Versions / Distros
It's not...
...JVM Configuration / Tuning
...Memory / Heap Analysis
What we'll cover...
Using Java in your ColdFusion Apps
When? How? 🤔
And when you don't need Java!
With lots of code examples!
Java can be intimidating
One step
at a time
Lets Get Started!
When...
Do you need Java?
Take advantage of a Java Library
Performance Optimization
Extended Functionality
Version or Engine Limitations
How?
Creating Java Objects
system = createObject("java", "java.lang.System");
writeDump( system.getenv() );
Creating Java Objects
// Requires Adobe ColdFusion 2018+
system = new java( "java.lang.System" );
writeDump( system.getenv() );
new java()
Go vote and/or follow the ticket!
Standard Library
What Version of Java is ColdFusion Using?
🤔
java.lang.System
system = createObject( "java", "java.lang.System" );
writeDump( system.getProperty("java.version") );
Give it a try!
Pause ⏸
// Introduced in Adobe ColdFusion 2018 and Lucee 5
writeDump( server.system.properties["java.version"] );
Do you need Java here?
How do I access Environment variables?
🤔
java.lang.System
var system = createObject('java', 'java.lang.System');
for ( var key in secrets ) {
var envValue = system.getenv( secrets[key] );
if ( !isNull(envValue) && envValue.len() ) {
variables[ key ] = envValue;
continue;
}
var propValue = system.getProperty( secrets[key] );
if ( !isNull(propValue) && propValue.len() ) {
variables[ key ] = propValue;
}
}
Pause ⏸
// Introduced in Adobe ColdFusion 2018 and Lucee 5
writeDump( server.system.environment );
Do you need Java here?
How do I write to stdout?
🤔
java.lang.System
stdout = createObject( "java", "java.lang.System" ).out;
stderr = createObject( "java", "java.lang.System" ).err;
stdout.println( "ahhhhh... information." );
stderr.println( "AHHHHH! ERRORS!" );
Pause ⏸
// Requires Lucee
systemOutput( "ahhhhh... information." );
systemOutput( "AHHHHH! ERRORS!", false, true );
Do you need Java here?
java.lang.System.out
function writeToConsole(required message) {
var args = arguments.copy();
args["timestamp"] = now().dateTimeFormat("iso");
stdout = createObject( "java", "java.lang.System" ).out;
stdout.println(serializeJSON(args));
}
writeToConsole( 'testing' );
How can I write a newline in a string in ColdFusion?
🤔
java.lang.System
system = createObject( "java", "java.lang.System" );
nl = system.getProperty("line.separator");
Pause ⏸
// Requires Lucee
newLine()
Do you need Java here?
How can I tell if it's a leap year?
🤔
java.util.GregorianCalendar
<CFOBJECT ACTION="CREATE" TYPE="Java"
CLASS="java.util.GregorianCalendar" NAME="myCalendar">
<CFSET is2001LeapYear = myCalendar.isLeapYear(2001)>
<CFSET theYear = myCalendar.get(myCalendar.YEAR)>
<CFSET theMonth = myCalendar.get(myCalendar.MONTH) + 1>
<CFSET theDay = myCalendar.get(myCalendar.DATE)>
<cfoutput>
<html>
<body>Is 2001 a leap-year? <b>#is2001LeapYear#</b>
<p>Today is the <b>#theMonth# / #theDay# / #theYear#</b>
</body>
</html>
</cfoutput>
That code was 21 years old!
🤯
Pause ⏸
// Introduced in some time after 2001
writeDump( isLeapYear(2001) );
You don't need Java here!
Can I preserve the order of keys in a struct?
🤔
java.util.LinkedHashMap
serial = createObject("java","java.util.LinkedHashMap").init();
serial.a = 1;
serial.b = 2;
serial.c = 3;
writeDump( serial );
Pause ⏸
// Introduced in Adobe ColdFusion 2016 and Lucee 5
serial = structNew( "ordered" );
serial.a = 1;
serial.b = 2;
serial.c = 3;
writeDump( serial );
Do you need Java here?
How do I create a standardized UUID?
🤔
java.util.UUID
uuid = createObject( "java", "java.util.UUID" );
writeDump( uuid.randomUUID().toString() );
Pause ⏸
// Requires Lucee
writeDump( createGUID() );
Do you need Java here?
How do I return the local hostname of the server?
🤔
java.net.InetAddress
function getHostname(){
return createObject( 'java', 'java.net.InetAddress' )
.getLocalHost()
.getHostName();
}
writeDump( getHostname() );
How do I work with Unix (Epoch) timestamps?
🤔
java.time.Instant
timestamp = 1661100546000;
instant = createObject("java","java.time.Instant").ofEpochMilli(timestamp);
date_time = createObject("java","java.util.Date").from( instant );
result = dateTimeFormat( date_time, 'full' );
writeDump(result);
So can I generate a Unix (Epoch) timestamp?
🤔
java.time.Instant
date_time = "2007-12-03T10:15:30.00Z";
instant = createObject("java","java.time.Instant").parse(date_time);
writeDump(instant.toEpochMilli());
instant = createObject("java", "java.time.Instant");
writeDump( instant.now().getEpochSecond() );
Can I gzip text strings?
🤔
java.util.zip.GZIPOutputStream
function gzip(required string str) {
if (!str.length()) {
return str;
}
var obj = createObject('java', 'java.io.ByteArrayOutputStream').init();
var gzip = createObject('java', 'java.util.zip.GZIPOutputStream').init(obj);
gzip.write(str.getBytes('UTF-8'));
gzip.close();
return binaryEncode(obj.toByteArray(), 'base64');
}
str = '“It is not the critic who counts; not the man who points out how the strong man stumbles, or where the doer of deeds could have done them better. The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood; who strives valiantly; who errs, who comes short again and again, because there is no effort without error and shortcoming; but who does actually strive to do the deeds; who knows great enthusiasms, the great devotions; who spends himself in a worthy cause; who at the best knows in the end the triumph of high achievement, and who at the worst, if he fails, at least fails while daring greatly, so that his place shall never be with those cold and timid souls who neither know victory nor defeat.”';
compressed = gzip(str);
writeDump(compressed);
size = [
"Original": arrayLen(str.getBytes()),
"Gzipped": arrayLen(compressed.getBytes())
];
writeDump(size);
Can I un-gzip compressed text strings?
🤔
java.util.zip.GZIPInputStream
function ungzip(required string str) {
var buffReader = createObject('java', 'java.io.BufferedReader').init(
createObject('java', 'java.io.InputStreamReader').init(
createObject('java', 'java.util.zip.GZIPInputStream').init(
createObject('java', 'java.io.ByteArrayInputStream').init(
toBinary(arguments.str))
)
)
);
var result = buffReader.readLine();
return result;
}
str = 'H4sIAAAAAAAAAFVS25HcMAxrhQV4roGtIP9pQLboFSd67Ii0Pf67QpLmrpKA0k7m8mWZhEAA1Nfn7x9GolSbkSWmrYvJRldqtLWjmj7+tUqoo/5qgjq1wyi1a7TUeqvPgVA7yppZF2odcO48ELFxp7ZTZI7q1DlSCqc36kAUWtmM+wf9HDI4iqGUwatk7T8F0Bs2O0LON0kdrdC5hsW7yrSHjR1UQgcPrTfFQ41CjaQXh3lac2vxMfggX05WOkOWUC3fs8y96/KOoqCtqXXcfQbMdIZxWiByC4cOE51nlsT77thLLHlOYEIaY75zgE7q80ErWk6PcL45mmrcc5y2R2ZT0q/aLqVndxNcLR0qQQtUOm6WI5/NpNX3DX1xReJJinLePa5AFzSkm4bsiQpzxSsjpjnjnSsujy80HeWVfIVJnglqk/DJBSKWYewbC+gVVQHUdyEZ+tDKHMA+/oGWDGOhI4epO98LqfsFMiHEV/YlakIkVDGpQ9zIExDf8dbwgnywSRHkihelQ0Rl8U0MG3TKZq3fWElHMDvmfHx9/vkLKBERbfYCAAA=';
writeDump(ungzip(str));
How can I easily parse URLS?
🤔
regex????
😧
java.net.URI
uri = 'https://blog.mattclemente.com/etc';
parsed_uri = createObject( "java","java.net.URI" ).init( uri );
uri_components = {
"Scheme": parsed_uri.getScheme(),
"Scheme Specific Part": parsed_uri.getSchemeSpecificPart(),
"Authority": parsed_uri.getAuthority(),
"User Info": parsed_uri.getUserInfo(),
"Host": parsed_uri.getHost(),
"Port": parsed_uri.getPort(),
"Path": parsed_uri.getPath(),
"Query": parsed_uri.getQuery(),
"Fragment": parsed_uri.getFragment()
}
writeDump( uri_components );
java.net.URI ⚔ java.net.URL
🧐
Can I generate URL Safe Base64 Encoding?
🤔
java.util.Base64
function urlSafeBase64Encode(str) {
return createObject("java", "java.util.Base64")
.getUrlEncoder()
.withoutPadding()
.encodeToString(str.getBytes("UTF-8"));
}
str = "subjects?_d=1"
base64 = toBase64(str);
writeDump({ "Standard Base64": base64});
urlSafeBase64 = urlSafeBase64Encode(str);
writeDump({ "URL Safe Base64": urlSafeBase64 });
java.util.Base64
function urlSafeBase64Encode(str) {
return createObject("java", "java.util.Base64")
.getUrlEncoder()
.withoutPadding()
.encodeToString(str.getBytes("UTF-8"));
}
function urlSafeBase64Decode(str) {
var bytes = createObject("java", "java.util.Base64")
.getUrlDecoder()
.decode(str);
return createObject("java", "java.lang.String").init(bytes);
}
urlSafeBase64 = urlSafeBase64Encode("subjects?_d=1");
writeDump({ "URL Safe Base64": urlSafeBase64 });
writeDump({ "Decoded": urlSafeBase64Decode(urlSafeBase64)});
How can I randomly shuffle elements in a list?
🤔
It is best to shuffle (randomize) the list of fallback hosts at init time in order to ensure load balancing across clients.
books = [
"Pilgrim at Tinker Creek",
"Long Day's Journey into Night",
"We are in a Book!",
"A Confederacy of Dunces",
"Pride and Prejudice"
];
createObject('java','java.util.Collections').Shuffle(books);
writeDump(books);
java.util.Collections.Shuffle()
What if I need to cycle through the list?
🤔
books = [
"Pilgrim at Tinker Creek",
"Long Day's Journey into Night",
"We are in a Book!",
"A Confederacy of Dunces",
"Pride and Prejudice"
];
writeDump(books);
collection = createObject('java','java.util.Collections');
collection.Rotate(books,-1);
writeDump(books);
collection.Rotate(books,-1);
writeDump(books);
java.util.Collections.Rotate()
What else can I do with these "Collections"?
🤔
books = [
"Pilgrim at Tinker Creek",
"Long Day's Journey into Night",
"We are in a Book!",
"A Confederacy of Dunces",
"Pride and Prejudice"
];
writeDump(books);
createObject('java','java.util.Collections').Reverse(books);
writeDump(books);
min = createObject('java','java.util.Collections').min(books);
writeDump({"min": min});
max = createObject('java','java.util.Collections').max(books);
writeDump({"max": max});
createObject('java','java.util.Collections').swap(books,0,1);
writeDump(books);
java.util.Collections
Can I perform DNS lookups?
🤔
com.sun.jndi.dns.DnsContextFactory
function dnsLookup(domain, type, dnsServer = "8.8.8.8", timeout = 2000, retries = 1){
var dnsRecords = [];
var env = CreateObject('java','java.util.Hashtable');
env.put('java.naming.factory.initial','com.sun.jndi.dns.DnsContextFactory');
env.put('java.naming.provider.url', 'dns://#dnsServer#');
env.put('com.sun.jndi.dns.timeout.initial', javaCast('string', timeout));
env.put('com.sun.jndi.dns.timeout.retries', javaCast( 'string', retries));
var dirContext = CreateObject('java', 'javax.naming.directory.InitialDirContext');
dirContext.init( env );
try {
var records = dirContext.getAttributes( domain, [ type ] ).get( type ).getAll();
while( records.hasMore() ) {
var record = records.next().ToString();
dnsRecords.append( record );
}
} catch ( any e ){} //if there are no records, the lookup fails
return dnsRecords;
}
mxRecords = dnsLookup( "mattclemente.com", "MX" );
writeDump( mxRecords );
How can I do faster string concatenation?
🤔
start = getTickCount();
sys = createObject( "java", "java.lang.System" );
nl = sys.getProperty("line.separator");
csvstr = "Email,Rand" & nl;
cfloop( from=1, to=50000, index="i" ){
csvstr &= "#i#@test.com,";
csvstr &= "#randRange(1,1000)#"
csvstr &= nl;
}
result = {"Time": getTickCount() - start}
writeDump(result);
The Problem
start = getTickCount();
sys = createObject( "java", "java.lang.System" );
nl = sys.getProperty("line.separator");
csvstr = "Email,Rand" & nl;
cfloop( from=1, to=50000, index="i" ){
csvstr &= "#i#@test.com,#randRange(1,1000)##nl#";
}
result = {"Time": getTickCount() - start}
writeDump(result);
ColdFusion Solution #1
start = getTickCount();
sys = createObject( "java", "java.lang.System" );
nl = sys.getProperty("line.separator");
csvstr = createObject("java","java.lang.StringBuffer");
csvstr.append("Email,Rand" & nl );
cfloop( from=1, to=50000, index="i" ){
csvstr.append("#i#@test.com," & randRange(1,1000) & nl);
}
result = {"Time": getTickCount() - start}
writeDump(result);
java.lang.StringBuffer
Pause ⏸
Do you need Java here?
start = getTickCount();
arr = ["Email,Rand"];
cfloop( from=1, to=50000, index="i" ){
arr.append("#i#@test.com,#randRange(1,1000)#");
}
sys = createObject( "java", "java.lang.System" );
nl = sys.getProperty("line.separator");
csvstr = arr.toList( nl );
result = {"Time": getTickCount() - start}
writeDump(result);
ColdFusion Solution #2
start = getTickCount();
sys = createObject( "java", "java.lang.System" );
nl = sys.getProperty("line.separator");
savecontent variable="csvstr" {
writeOutput("Email,Rand");
cfloop( from=1, to=50000, index="i" ){
writeOutput("#i#@test.com" & "," & randRange(1,1000) & nl);
}
};
result = {"Time": getTickCount() - start}
writeDump(result);
ColdFusion Solution #3
More to learn!
Community Libraries
How to Load Jars
What's a .jar?
Java Archive
It's basically a zip.
this.javaSettings
// defaults
this.javaSettings = {
// paths to directories containing Java jars / classes
loadPaths: [], // only required setting
loadColdFusionClassPath: false,
reloadOnChange: false,
watchInterval: 60, //seconds
watchExtensions: "jar,class"
}
this.javaSettings
// Application.cfc
this.javaSettings = {
loadPaths: [
".\java\myjar.jar",
".\java_lib\"
]
}
// Application.cfc
this.javaSettings = {
loadPaths: directoryList(
path = expandPath( "/lib" ),
recurse = true,
type = 'file' )
};
createObject()
This is Lucee specific!
createObject('java',class,context)
createObject()
Go vote for Adobe to add support!
Other Approaches
JSOUP
HTML parser, built for HTML editing, cleaning, scraping, and XSS safety
Application Structure
Jsoup = createObject("java", "org.jsoup.Jsoup");
uri = "https://blog.mattclemente.com";
doc = Jsoup.connect( uri ).get();
title = doc.title();
writeDump(title);
links = doc.select("a[href]");
// writeDump( var='#links#', abort='true' );
for( link in links ){
parsed = {
"Text": link.wholeText(),
"href": link.attr("abs:href")
}
writeDump( parsed );
}
Parsing HTML
Parsing HTML - Output
Antisamy
Fast, configurable cleansing of HTML coming from untrusted sources.
Application Structure
Sanitizing HTML
sanitizer = createObject("java","org.owasp.validator.html.AntiSamy");
policyFile = expandPath( 'config/default.xml' );
str = "<p> This is a test for
<h1 onclick= “alert(‘malicious code’);” > AntiSamy </h1>";
clean_results = sanitizer.scan( str, policyFile );
result = [
"Input": str,
"Cleaned": clean_results.getCleanHTML(),
"Errors": clean_results.getErrorMessages()
]
writeDump(result);
Sanitizing HTML - Result
// Input
<p> This is a test for <h1 onclick= “alert(‘malicious code’);” > AntiSamy </h1>
// Cleaned
<p> This is a test for </p> <h1> AntiSamy </h1>
// Error message
The h1 tag contained an attribute that we could not process. The onclick attribute has been filtered out, but the tag is still in place. The value of the attribute was "alert(malicious".
Pause ⏸
// Requires Adobe ColdFusion 11+
unsafeHtml = "<p> This is a test for <h1 onclick= “alert(‘malicious code’);” > AntiSamy </h1>";
writeDump( isSafeHTML(unsafeHtml) );
writeDump( getSafeHTML(unsafeHtml) );
Do you need Java here?
Go vote and/or follow the ticket!
getSafeHTML() isSafeHTML()
eo-yaml
Read and generate YAML
# Project Info. This comment refers to the whole document.
---
firstName: John
lastName: Doe
age: 20
grades:
CS: 10
Math: 9
other:
- 1
- 2
- 3
Reading Yaml Files
eoyaml = createObject("java", "com.amihaiemil.eoyaml.Yaml");
yaml_file = createObject("java", "java.io.File").init("example.yaml");
yml_parsed = eoyaml.createYamlInput(yaml_file).readYamlMapping();
iterator = yml_parsed.keys().iterator();
while( iterator.hasNext() ) {
key = iterator.next();
writedump(key.value());
writedump(yml_parsed.value(key.value()));
}
Reading Yaml Files
writeDump( var='#yml_parsed.comment().value()#', abort='true' );
Reading Yaml Files - Result
yaml = eoyaml.createYamlMappingBuilder()
.add("name", "Elizabeth")
.add(
"siblings",
eoyaml.createYamlSequenceBuilder()
.add("Jane")
.add("Mary")
.add("Kitty")
.add("Lydia")
.build()
).add(
"suitors",
eoyaml.createYamlSequenceBuilder()
.add("Darcy")
.add("Wickham")
.add("Collins")
.build()
).build();
Writing Yaml Files
# Output of previous slide
name: Elizabeth
siblings:
- Jane
- Mary
- Kitty
- Lydia
suitors:
- Darcy
- Wickham
- Collins
Writing Yaml Files
AWS Java SDK
Interact with all things AWS
Resources
Mustache
Utilize the Mustache templating language
}
flexmark-java
Markdown parser and more.
Security Stuff
Argon2id, BCrypt, PBKDF2, and more
More to explore!
- BoltHTTP (Apache HttpComponents)
- Playwright Java Library with ColdFusion (Gist)
- LaunchDarkly CFML SDK
- pdfbox.cfc
Matthew Clemente
Cold Brews
Getting Started with Java
in Your CFML Apps
Resources
Adobe Documentation
Additional
Cold Brews: Getting Started with Java in Your CFML Apps
By mjclemente
Cold Brews: Getting Started with Java in Your CFML Apps
Presentation for Into the Box 2022
- 874