I recently inherited a project that had customized iphone keyboards by adding a toolbar following the techniques in http://www.iphonedevsdk.com/forum/iphone-sdk-tutorials/7350-adding-subviews-custimize-keyboard.html.
Sadly, this code behaves badly in the new SDK 3.2, it crashes. First time because of a index out of bounds, and once that was fixed then an infinite loop on keyboardDidShow. (And yes I did catch the object name change too). Luckily, 3.2 provides a new handy method to simply add the inputAccessoryView with out all the previous fuss.
But, do you want to release just a 3.2 app? If your in my position, the business sponsors do not want to hear that their hard won customized toolbar will only be seen on the iPad for a while. They expect backwards compatibility.
I solved this dilemma by using the UIInputTextField instancesRespondTo inputAccessoryView to guard the call that sets up the keyboard event listeners required in the older solution, so that only on 3.1 devices will the keyboard intercepts be executed. Then I setup a new message type AddToolbar to be called by TextFieldDelegates for fields where the toolbars will be needed.
Note that Apple does not 'publish' the Notification that triggers shouldTextBeginEditing or textFieldDidBeginEditing so instead of just having a global delegate I instead trigger this new AddToolbar notification as part of my TextFieldDelegate response.
The new message listener again checks for inputAccessoryView support and in 3.2 code makes the call to add the new Toolbar.
Thursday, April 29, 2010
Saturday, April 24, 2010
A Trick for EasyMock with Legacy Code...
... where "Legacy Code" is, to paraphrase Michael C. Feathers, any code that's been in production longer than 3 months. Or in my case a new project coded over a year ago, by consultants, on a tight schedule. Lots of classes had been developed without consideration for unit testing which means lots of inter-dependent code without any hooks for dependency injection.
For example, there is a standard Config utility class that loads a property file and then provides getter methods for the values.
In this project's case, I agree that the access to the config needs to be read only, as only bugs and mischief would result if later generations of developers thought that public or protected access to the Properties meant the config was expected to change at run-time. I also like the static behavior as it makes for clean code with no extraneous getInstance() or setConfig() calls everywhere the class is used.
On the other hand, I am simply too lazy to enjoy having to 1) set up my local environment to exactly match server paths. 2) build and deploy my code to test every code change and 3) stop and start the server to test every property permutation.
So, the challenge with this legacy code was to figure out how to inject properties at Test time without any impact on the existing code. Thankfully in Java I have Reflection and EasyMock.
First - a snapshot of the config class:
public class AppConfig {
private static Properties applicationProperties;
public static void loadConfig(ServletContext context){
... load files into appProperites
//don't worry about this being static on
//a constructed object it has been working over a year now..
}
public static String getProperty(String propKey) {
return appProperties.getProperty(propKey);
}
}
However, good isolated unit tests require I bypass all dependencies on file loading etc. so the first trick is abusing reflection to give me a point to inject a config mock object. Then I can create an EasyMock wrapper on the Properties object to inject which ever specific property and value my client code will need.
// written as a junit method for simplicity here
import org.easyMock.classextension.*;
public void testSomeObject() {
AppConfig env = new AppConfig();
Class c = env.getClass();
try {
Field appProps = c.getDeclaredField("applicationProperties");
appProps.setAccessible(true);
Properties overRideProps = EasyMock.createMock(Properties.class);
EasyMock.expect(overRideProperties.getProperty("testkey")).andReturn("false"); //sets up our test property
EasyMock.replay(overRideProps); // readies mock object to act during test.
appProps.set(env, overRideProps); //puts our mock back into AppConfig object
} catch (SecurityException e1) {
fail ("denied access to reset applicationProperties to public " + e.toString());
} catch (NoSuchFieldException e2) {
fail ("applicationProperties field name changed " + e.toString());
} catch (IllegalAccessException e3) {
fail ( "Unable to override properties in AppConfig " + e.toString());
} catch (IllegalArgumentException e4) {
fail ( "Unable to override properties in AppConfig " + e.toString());
//Note that you might see this exception if you import wrong form of EasyMock must use classextension
}
SomeObject so = new SomeObject();
SomeState testState = new SomeState();
... setup testState ...
String testResult = so.doSomeMethod(testState);
// If the above method does not call the expected property test will fail with EasyMock exception.
// otherwise it will fail if the following assertion fails.
assertEquals( "expectedResult", testResult);
}
Finally, a few words of caution on this style of testing
This test is brittle, it has knowledge of internal code working that would be better it not have. Now neither the Properties field name in AppConfig, nor the property key String can change without breaking this code. So there is a risk that a future developer will curse my name for requiring him to fix test cases for no good reason. If this were not Stable Legacy Code I would be more concerned about this risk.
This test case doesn't guarantee the system will behave as expected once deployed. There are no protections against keys changing in the property file used to load the AppConfig causing runtime defects. So some form of integration testing is needed to ensure the overall system works as intended later.
EasyMock may seem like overkill here, as I could just as easily injected a plain old Properties object. The benefit of EasyMock is that I can see exactly where the test fails and why - wrong key is used or no check is made. For all other reasons the final assert may fail I've got to go in and spend time debugging.
For example, there is a standard Config utility class that loads a property file and then provides getter methods for the values.
- Hurdle #1: The Utility class only expects a ServletContext as a means to getting the file name to load.
- Hurdle #2: Various path manipulations have been hard-coded in the file loading method as well.
- Hurdle #3: The internal properties object holding the values is private accessor, designed to be read only by client classes.
- Hurdle #4: Set up for ease of use with static method fields, so I can't just create an instance of my own or subclass easily.
In this project's case, I agree that the access to the config needs to be read only, as only bugs and mischief would result if later generations of developers thought that public or protected access to the Properties meant the config was expected to change at run-time. I also like the static behavior as it makes for clean code with no extraneous getInstance() or setConfig() calls everywhere the class is used.
On the other hand, I am simply too lazy to enjoy having to 1) set up my local environment to exactly match server paths. 2) build and deploy my code to test every code change and 3) stop and start the server to test every property permutation.
So, the challenge with this legacy code was to figure out how to inject properties at Test time without any impact on the existing code. Thankfully in Java I have Reflection and EasyMock.
First - a snapshot of the config class:
public class AppConfig {
private static Properties applicationProperties;
public static void loadConfig(ServletContext context){
... load files into appProperites
//don't worry about this being static on
//a constructed object it has been working over a year now..
}
public static String getProperty(String propKey) {
return appProperties.getProperty(propKey);
}
}
However, good isolated unit tests require I bypass all dependencies on file loading etc. so the first trick is abusing reflection to give me a point to inject a config mock object. Then I can create an EasyMock wrapper on the Properties object to inject which ever specific property and value my client code will need.
// written as a junit method for simplicity here
import org.easyMock.classextension.*;
public void testSomeObject() {
AppConfig env = new AppConfig();
Class c = env.getClass();
try {
Field appProps = c.getDeclaredField("applicationProperties");
appProps.setAccessible(true);
Properties overRideProps = EasyMock.createMock(Properties.class);
EasyMock.expect(overRideProperties.getProperty("testkey")).andReturn("false"); //sets up our test property
EasyMock.replay(overRideProps); // readies mock object to act during test.
appProps.set(env, overRideProps); //puts our mock back into AppConfig object
} catch (SecurityException e1) {
fail ("denied access to reset applicationProperties to public " + e.toString());
} catch (NoSuchFieldException e2) {
fail ("applicationProperties field name changed " + e.toString());
} catch (IllegalAccessException e3) {
fail ( "Unable to override properties in AppConfig " + e.toString());
} catch (IllegalArgumentException e4) {
fail ( "Unable to override properties in AppConfig " + e.toString());
//Note that you might see this exception if you import wrong form of EasyMock must use classextension
}
SomeObject so = new SomeObject();
SomeState testState = new SomeState();
... setup testState ...
String testResult = so.doSomeMethod(testState);
// If the above method does not call the expected property test will fail with EasyMock exception.
// otherwise it will fail if the following assertion fails.
assertEquals( "expectedResult", testResult);
}
Finally, a few words of caution on this style of testing
This test is brittle, it has knowledge of internal code working that would be better it not have. Now neither the Properties field name in AppConfig, nor the property key String can change without breaking this code. So there is a risk that a future developer will curse my name for requiring him to fix test cases for no good reason. If this were not Stable Legacy Code I would be more concerned about this risk.
This test case doesn't guarantee the system will behave as expected once deployed. There are no protections against keys changing in the property file used to load the AppConfig causing runtime defects. So some form of integration testing is needed to ensure the overall system works as intended later.
EasyMock may seem like overkill here, as I could just as easily injected a plain old Properties object. The benefit of EasyMock is that I can see exactly where the test fails and why - wrong key is used or no check is made. For all other reasons the final assert may fail I've got to go in and spend time debugging.
Thursday, February 4, 2010
Forget Part 1 - done right Groovy don't need a part 2
I had put this project on the shelf for time. New solution is half the code, requires only the one script file, and does even more.
Groovy's so flexible I can see where this could be condensed further, but then I'd have to double the comments to remember what it's doing next time I go to modify it.
def cruiseServer = 'http://build.server.com:9000'
def uploaddir = "user@123.123.123.123:/path/to/deployment/dir"
def downloaddir = 'D:\\localbuild\\downloaddir\\'
def rssPath = '/cruisebuild/rss/'
def artifactPath = '/cruisecontrol/artifacts'
//The common list of assets to download. With this list structure I can just comment out
// any asset to skip over each release or do the full download. Also can control if I want latest
// and greatest or a specific tested version.
def projects = [
//['comment out', 'assets not needed', 'latest'],
['Build-Project1', 'assetname.ear', 'latest'],
['Build-Project2', 'assestname.war', '12.12.1002']
]
//for the identified collection, do the download
projects.each() { project, ear, version ->
//get rss feed into a navigable object
def rssFeed = new XmlParser().parse( cruiseServer + rssPath + project).channel[0]
//get either the latest good build OR a specific version number
def passeditem
if ('latest'.equals(version) {
passeditem = rssFeed.item.find{ it.description.text() == 'Build passed' }
} else {
passeditem = rssFeed.item.find{ it.link.text() =~ version )
}
//link in RSS feed goes to the cruisebuild details, but what I need is asset download path.
def link = passeditem.link.text()
//reprocess the build number from link based on regex pattern for 4 sets digits w/ dot separator.
def buildMatcher = ( link =~ /\d+[.]\d+[.]\d+[.]\d+/ )
def buildNo = buildMatcher[0]
//Then the crucial info is the cruisebuild ID 14 digit number
def matcher = ( link =~ /\d{14}/)
def assetNo = matcher[0]
//so I can publish which ears were deployed
println "${project}.ear (V-${buildNo})"
//Now for the cool automatic download
def srcLoc = "${cruiseServer}${artifactPath}${project}/${assetNo}/${ear}"
def file = new File(dwnldDir + srcLoc.tokenize("/")[-1])
def out = new BufferedOutputStream(new FileOutputStream(file))
out <<>
//publish file size to confirm end of download
println file.length()
out.close()
} // end of download closure
//ah the miracle of AntBuilder - my files loaded straight to server after download
ant = new AntBuilder()
//note: in eclipse scp requires some path configuration.
//google the error you get when this runs to find correct jars for your version.
ant.scp( todir: "${uploadDir}",
password: "opensesme",
trust: "true" {
fileset(dir:"$dwnldDir") {
//this little closure ensures I only upload new assets.
//pretty cool to be able to mix builder syntax and script code.
projects.each() { project, ear, version ->
include(name: "$ear")
} //end projects.each closure
} // end fileset closure
} //end ant.scp closure
Labels:
AntBuilder,
CruiseControl,
Groovy,
RSS feed parsing
Tuesday, April 7, 2009
Groovy CruiseControl Helper - part 1 RSS and Regex
I've been wasting entirely too much time deploying builds lately as our CruiseControl instance produces upwards of 35 builds, of which I only care about 4. Not to mention that downloading each ear file is at least 3 page 'clicks'. Ignoring for now that CruiseControl would happily deploy my ears for me (team's CruiseControl guru is overbooked right now), I've started building a Groovy utility to leverage the RSS feeds produced by CruiseControl in order to run an automatic pull of the latest builds for my 4 target ears.
I started tinkering with examples found in "Groovy In Action" and in Netbeans, but moved over to Eclipse 3.4.1 when things were ready to implement as that's the standard at work. Netbeans was more 'Groovyish' and very easy to start scripting with, whereas Eclipse is more 'Javaish' expecting you to produce classes rather than 'scripts'
In the end I built one Class to handle the RSS and information parsing and one Script to act as my main and run my new process.
My Class simply opens an RSS feed, pulls data from the top item and parses out the stuff I need to find my assets for deployment.
/*
For a specific RSS feed and project. Get the key data for the latest build
*/
public class GetRss {
private myBase;
private myProject;
private buildNo;
private assetNo;
GetRss (String base, String project) {
myBase = base;
myProject = project;
}
void doRss()
{
//open the Rss Feed URL, parse date into XML Document
def items = new XmlParser().parse(myBase + myProject).channel[0].item
//GPath notation to get to elements of interest
// title tells me if this build passed or failed
println items[0].title.text()
//The link is to build HTML - I want only some of this info
parseLink( items[0].link.text())
}
/*
parseLink uses regular expressions to pull out the two items I need from the link
Build No is what I will use to identify the build to QA ##.##.##.##
Asset No is what CruiseControl uses to uniquely identify build results - 14 digit number
*/
void parseLink(String link)
{
//Link contains build # - what the build will be know by in the real world
// build number is pattern of 4 sets of digits separated by .
def buildMatcher = ( link =~ /-\d+[.]\d+[.]\d+[.]\d+/ )
buildNo = matcher[0]
//link also contains CruiseControl build ID - 14 digit number
def matcher = ( link =~ /\d{14}/ )
assetNo = matcher[0]
}
Part 1 - merely generates URLs for where each ear file is stored by the CruiseControl process. So instead of many page clicks to download. I can run the following script and get 4 URLs ready to download the assets from. Stay tuned for Part2 where I will use AntBuilder and Groovy to automatically FTP these assets to where I need to stage them...
//The common paths set by cruisecontrol
def cruiseServer = 'http://mybuild.server.com:8081'
def allRSS = "$cruiseServer/cruisecontrol/rss/"
def allAsset = "$cruiseServer/crusiecontrol/artifacts"
//Read RSS for Project1 and get key data
GetRss uiservices = new GetRss( allRss, "Project1-BuildWar")
uiservices.doRss()
//Print the line with build No and URL to deployment asset
println " $uiservices.buildNo $allAsset$uiservices.myProject/$uiservices.assetNo/project1.war"
//... Repeated above for each additional project
The script outputs two lines, first the item title with time of build and status. Then a second line with the build No and a link that I can cut and paste into browser to initiate the download of the deployment asset.
Example output for first project
Tue Apr 07 20:41:47 EDT 2009, passed
-10.12.1.191 http://mybuild.server.com:8081/cruisecontrol/artifacts/Project1-BuildWar/20090403180111.project1.war
As mentioned, in part 2 I will develop the code to directly download the build assets using the URLs generated in part 1.
Labels:
CruiseControl,
Groovy,
Regex,
RSS feed parsing
Friday, February 27, 2009
Okay, why I really want to learn Groovy is that I need to adapt Unit Testing to a large, ancient legacy java application. With no existing tests, and more 'spaghetti' than will be eaten in Italy this year, I'm trying to inject mocks and stubs without having to refactor every class.
I've run the sample found at http://docs.codehaus.org/display/GROOVY/Using+the+Delegating+Meta+Class where the String class behavior is changed during a script run. However, the change is not replicated when the string.toString() method is called inside of a Java class (triggered from the Groovy Script).
I figure I'm missing a crucial understanding of the Groovy vs Java Classloader... Or is that all real coders always design objects with setDepenedency() methods that allow for easy code injection?
Thursday, February 26, 2009
Regex File Search with Groovy
I needed something interesting to get me going. And then I moved to a new team at work, losing access to my nice tool rich linux account, leaving me with only a shiny new Dell Windows laptop and a need to quickly hunt through a large, legacy codebase. Hooray - Groovy to the rescue!
The first pass at this script took me about 2 hours from Groovy Console install to working code. This cleaned up version took me maybe another 2 of tweaking the regex and collapsing code down into more compact closures. For reference I leaned heavily on Google and the working with files and I/O section from "Groovy in Action".
(Prerequisite note on starting point for true beginners - download the installer from groovy.codehaus.org, following code was developed and run from the GroovyConsole
My apologies for any syntax bugs introduced in moving code into this format)
Quick Summary of lessons in developing this code:
- If you don't call flush on writing to a file, file most often empty when script exits.
- Explicitly calling java.util.Pattern does not produce the same matching behavior as using the Groovy notation
- I'm still a little confused on where is safe to use single or double quotes, I got lots of errors about parsing the script. Seemed like comment indicators don't completely insulate against the console recognizing quote marks.
- I'm not sure how much patience I'll have in the future for the java.io package!
//*************
//Walk through a set of files
//collects information about a target string into an output file.
//*******************
// no need to define type for variables, just use generic def keyword
def outputfile = new File("myresultsfile.out").newWriter()
//This is the class invented for ant
//spiders through directories to get list of files to search.
//list of prefixes identifies specific file types of interest.
FileNameFinder dirList = new FileNameFinder();
List sourcefiles = dirList.getFileNames("mysrcdirectory/", "**/*.jsp, **/*.java, **/*.js, **/*.javascript, **/*.properties, **/*.xml, **/*.conf, **/*.props")
//defining a holder for results. I want unique so using a set
Collection fileList = new HashSet();
//define a simple function to control where results are written.
//with closures the 'method' is simply defined as another type.
//Default input variable is it
def collectResults = {
println it
outputfile.writeLine(it)
}
//function takes three inputs filename, linenumber, and line
//for the line that holds the pattern
//write out the information to the output file
//save the filename in a set to generate a list of target files
def processfile = {
//defining specific function inputs instead of using default it
srcfile, srcline, src -> //newbies note the arrow signature it's important!
//find all text matches in the line,
//no need to mess with java.util classes
// Groovy's added simple syntax to generate a matcher (like Perl)
def finder = ( src =~ /.*targetstring*/ )
if (finder.matches())
{
//write file and line number and matched results
fileList.add(srcfile)
//another favorite script feature available in Groovy
//just use token syntax to generate mix of variable and static output
collectResults( "${srcfile}^${srcline}^${src}")
}
else
{
//easy to debug - print information to sysout without all the typing.
println 'did not find ' + finder.pattern()
}
}
//Now for the meat of the script.
//Notice the easy for iteration syntax,
//define a list or collection and a variable to hold each reference (again see perl)
for ( sourceFil in sourcefiles){
//read file in
File fileHandle = new File(sourceFil)
Reader openFile = fileHandle.newReader()
//for each line - use the Groovy defined easy file line reader method.
// this method takes a closure and run it each line of a file,
// notice 'it' is the active line of file
openFile.eachLine{ processfile(sourceFil, openFile.getLineNumber(), it)}
}
//when done processing files flush output file to ensure capture of text
outputfile.flush()
//Also check if want to write out list of unique file names captured
if (fileList.size() > 0)
{
def chgFiles = new File("filesofinterest.out").newWriter()
//First line to tell me how many files were identified to contain the target pattern
chgFiles.writeLine(fileList.size().toString())
//again using a nifty Groovy method added to every list or collection type
//passing it a closure to execute for each element in the list
fileList.each{
chgFiles.writeLine(it)
println(it)
}
//ensuring the output gets written
chgFiles.flush()
}
How I got started with Groovy (and blogging about it)
My first exposure to Groovy happened at my local Java Users Group (www.ajug.org). We had a demo over a year ago by none other than Jeff Brown. I hate to admit that while I was completely blown away by that talk, I procrastinated actually getting my hands dirty with learning Groovy.
My first roadblock was being a complete novice to any kind of dynamic language. My extremely conservative corporate employer had up to now let the Javascript and Web 2.o revolution pass them by. I had written a few Perl scripts, but never for anything except as a workaround to some of the limitations to shell scripting. Groovy code doesn't make whole lotta sense until you can grok closures, and the lightweight syntax. Thankfully, a coworker pointed me to YUI Theater where Douglas Crockford explains Javascript as a real language. Now at least I understand the concepts of a robust dynamic language.
That of course leaves only the small problem of learning to use the language properly. I find book examples are never all that informative, it doesn't take much to wander off the reservation and end up really lost. I've recently been advised that lots of free expert advice is available, if only you post to a blog. Blame Jared Richardson for daring me to post a blog and share my dabblings with the universe at large.
Subscribe to:
Posts (Atom)