Well, my JQuery mobile based pages don't load in the Windows Mobile emulator or on the Windows Mobile devices used by our clients for UAT.
This is not good!!
Turns out that this is a similar issue that we have seen in the Richfaces 3.3 libraries and I am not sure that this is a known defect or not.
Windows Mobile browser doesn't support implicit toString() methods on objects when used in calls to colsole.log(String) and elements do not have an explicit toString() method.
That makes little sense, what do you mean?
Well, let us consider the simple logging statement below:
var myElement = $('myElementId');
console.log("found element [" + myElement + "]");
In just about all browsers this will work fine, but not in Windows Mobile browser (or IE8 strict mode, but that is another story).
The issue is that javascipt will call an implicit "toString() on the variable "myElement" and it is not defined in Windows Mobile browser and the script will stop executing.
Wow, that is pretty fucked up?
Yes it is.
What can I do to stop this?
You can either write you own toString() helper/utility method or use a better logging/debugging framework which wraps and manages these call.
For example:
var myElement = $('myElementId');
Log.info("found element [%s]", myElement);
var Log = {};
Log.info(msg, itemParam) {
// blah blah blah
//
// There are heaps of logging scripts on the net for you to use
// remember "Unless you need a wheel that isn't round
// then one has already been invented"
}
I hope this saves you some pain.
YepYep
A blog for the people who don't even know if they are being sarcastic
Monday, February 13, 2012
Thursday, January 19, 2012
Use Java reflection to find classes that implement an interface from a package
How do you find a set of Classes that implement and interface?
You do this (well, I did this).
final List<Class<?>> processorCandidates = ReflectionHelper.findClassesImpmenenting(HostDataProcessor.class, HostDataProcessor.class.getPackage());
And use this helper class:
public class ReflectionHelper {
public static List<Class<?>> findClassesImpmenenting(final Class<?> interfaceClass, final Package fromPackage) {
if (interfaceClass == null) {
Debug.println("Unknown subclass.");
return null;
}
if (fromPackage == null) {
Debug.println("Unknown package.");
return null;
}
final List<Class<?>> rVal = new ArrayList<Class<?>>();
try {
final Class<?>[] targets = getAllClassesFromPackage(fromPackage.getName());
if (targets != null) {
for (Class<?> aTarget : targets) {
if (aTarget == null) {
continue;
}
else if (aTarget.equals(interfaceClass)) {
Debug.println("Found the interface definition.");
continue;
}
else if (!interfaceClass.isAssignableFrom(aTarget)) {
Debug.println("Class '" + aTarget.getName() + "' is not a " + interfaceClass.getName());
continue;
}
else {
rVal.add(aTarget);
}
}
}
}
catch (ClassNotFoundException e) {
Debug.println("Error reading package name.");
Debug.printStackTrace(e, Debug.LOW_LEVEL);
}
catch (IOException e) {
Debug.println("Error reading classes in package.");
Debug.printStackTrace(e, Debug.LOW_LEVEL);
}
return rVal;
}
/**
* Load all classes from a package.
*
* @param packageName
* @return
* @throws ClassNotFoundException
* @throws IOException
*/
public static Class[] getAllClassesFromPackage(final String packageName) throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
List<File> dirs = new ArrayList<File>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
ArrayList<Class> classes = new ArrayList<Class>();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes.toArray(new Class[classes.size()]);
}
/**
* Find file in package.
*
* @param directory
* @param packageName
* @return
* @throws ClassNotFoundException
*/
public static List<Class<?>> findClasses(File directory, String packageName) throws ClassNotFoundException {
List<Class<?>> classes = new ArrayList<Class<?>>();
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
assert !file.getName().contains(".");
classes.addAll(findClasses(file, packageName + "." + file.getName()));
}
else if (file.getName().endsWith(".class")) {
classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
}
}
return classes;
}
}
which uses the two methods found here
Monday, December 26, 2011
One for the Hot Shots
Pop Quiz: A Windows OS security error occurs on a single node in your Oracle cluster, what does the cluster do?
a) Isolate the node by passing load to the rest of the cluster
b) Fail over to the replicated "Fail Over" cluster
c) Lock data transfer in and out of the cluster, lock every client's JDBC connection and cause a back log to form in the radio network which combine to be 6 hour outage requiring 8 hours of continuous phone calls and 12 hours of monitoring; or
d) Shoots the hostage
A little hint, It isn't "d)", but if it were, then you would wish you were the hostage.
Tuesday, October 19, 2010
Reading from jar file from classpath
I had a recent issue with "read all the files in folder from within the jar file that is in the class path". The standard solution is generate a resources file (in this case include all the files) and set it to a known location in the jar file. Then access the resource file, read the names and load the files from the stream.
I did it this way:
public class ZipFileUtil {
/**
* Lowercase extension names for zip or zipish files.
*/
private static final String[] zipExtensions = { ".zip", ".jar" };
/**
* Name of system property for java class path.
*/
private static final String CLASS_PATH_PROPERTY_NAME = "java.class.path";
/**
* Search the class path for a file name.
*
* This is slower if not case sensitive.
*
* @param fileName the file name
* @param caseSensitive the match for file name will be case sensitive
* @return a File or null if not found or if this isn't a zip (or zipish) file.
*/
public static File getFileFromJar(String fileName, final boolean caseSensitive) {
if (!isJarFile(fileName)) {
return null;
}
fileName = fileName.trim();
File rVal = null;
final String fullPath = System.getProperties().getProperty(CLASS_PATH_PROPERTY_NAME);
final String[] jars = fullPath.split(File.pathSeparator);
if (jars != null) {
for (String jarName : jars) {
jarName = jarName.trim();
if (jarName.endsWith(fileName) || (!caseSensitive && jarName.toLowerCase().endsWith(fileName.toLowerCase()))) {
return new File(jarName);
}
}
}
return rVal;
}
/**
* List all the file names contained in a jar/zip file.
*
* @param jarFile the jar/zip file to search
* @param target pattern to match (no wildcards)
* @return list of strings that are relative filenames that match the target pattern or null if this isn't a zip (or zipish) file.
* @throws IOException if an exception occurs
*/
public static List listMatchingContents(final File jarFile, final String target) throws IOException {
if (!isJarFile(jarFile)) {
return null;
}
final List rVal = new ArrayList();
ZipInputStream zis = new ZipInputStream(new FileInputStream(jarFile));
for (ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {
if (ze.getName().indexOf(target) > -1) {
rVal.add(ze.getName());
}
}
return rVal;
}
/**
* List all the file names contained in a jar/zip file.
*
* @param jarFilename the name of jar/zip file to search
* @param target pattern to match (no wildcards)
* @return list of strings that are relative filenames that match the target pattern or null if this isn't a zip (or zipish) file.
* @throws IOException if an exception occurs
*/
public static List listMatchingContents(final String jarFilename, final String target) throws IOException {
return listMatchingContents(new File(jarFilename), target);
}
/**
* Is this a zip file?.
*
* @param aFilename a file name
* @return true of false (true for yes it is a zipish file)
*/
public static boolean isJarFile(String aFilename) {
if (aFilename == null || aFilename.trim().length() == 0) {
return false;
}
aFilename = aFilename.trim().toLowerCase();
for (String anExtension : zipExtensions) {
if (aFilename.endsWith(anExtension)) {
return true;
}
}
return false;
}
/**
* Is this a zip file?.
*
* @param aFile a file
* @return true of false (true for yes it is a zipish file)
*/
public static boolean isJarFile(final File aFile) {
if (aFile == null) {
return false;
}
return isJarFile(aFile.getName());
}
}
Thursday, August 26, 2010
Too much of a (good?) thing, Be wary of what you ask for, A bird in the hand is just going to shit on you and other BS
So I now have both a 100Mb/s connection to the house (thanks Kev) and a Wifi enabled phone which has granted me the ability to hold all of the world's information in the palm of my hand.
The issue I have is that after checking my email a few times, looking at the latest election results and spamming facebook and twitter for 3 hours straight I have nothing else to do.
Eventually I found my way to a little know upstart website called YouTube. After watching both the video of a cat jumping out of a cardboard box and the video of the cat trying to climb through a box when it is far too fat the quality of content went down hill and down hill fast.
So after a week of the world at my finger tips I have realised that "the world" is best kept at arm's length.
FFS I am a spoilt little shit, why don't I just shut the hell up and watch some porn.
Wednesday, August 4, 2010
A DailyWTF Candidate
This from a build script that isn't far from my reach by a long way from my heart.
<!-- Make lowercase (Dont hate me for this, it is the cleanest way) -->
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(A)" replace="a" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(B)" replace="b" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(C)" replace="c" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(D)" replace="d" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(E)" replace="e" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(F)" replace="f" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(G)" replace="g" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(H)" replace="h" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(I)" replace="i" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(J)" replace="j" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(K)" replace="k" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(L)" replace="l" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(M)" replace="m" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(N)" replace="n" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(O)" replace="o" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(P)" replace="p" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(Q)" replace="q" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(R)" replace="r" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(S)" replace="s" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(T)" replace="t" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(U)" replace="u" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(V)" replace="v" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(W)" replace="w" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(X)" replace="x" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(Y)" replace="y" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(Z)" replace="z" global="true"/>
<!-- Make lowercase (Dont hate me for this, it is the cleanest way) -->
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(A)" replace="a" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(B)" replace="b" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(C)" replace="c" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(D)" replace="d" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(E)" replace="e" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(F)" replace="f" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(G)" replace="g" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(H)" replace="h" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(I)" replace="i" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(J)" replace="j" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(K)" replace="k" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(L)" replace="l" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(M)" replace="m" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(N)" replace="n" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(O)" replace="o" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(P)" replace="p" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(Q)" replace="q" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(R)" replace="r" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(S)" replace="s" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(T)" replace="t" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(U)" replace="u" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(V)" replace="v" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(W)" replace="w" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(X)" replace="x" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(Y)" replace="y" global="true"/>
<propertyregex override="yes" property="dir_name" input="${dir_name}" regexp="(Z)" replace="z" global="true"/>
Monday, July 12, 2010
Datasets - large, fast but not cheap and absolutely not easy
Todays task: Make the large data set load quickly, render seamlessly and run efficiently.
In the end, there is just only so much you can do.
This excerpt from an email explains the issue that the users were having when "loading the module": (note that it is edited to protect product secrets while context remains)
In the end, there is just only so much you can do.
This excerpt from an email explains the issue that the users were having when "loading the module": (note that it is edited to protect product secrets while context remains)
.... the [largest module source] uses 360MB of RAM to load the [items] (all 465,000 of them at just over 800 bytes each) from the [data source] and render the schematic on the screen. This is on top of the 170MB that the application usually requires.
With the latest changes, 98% of this RAM is either freed and released or reused when a different [module source] is opened but a user still requires 530MB of heap space for this to run .....
Saturday, July 10, 2010
Saturday, July 3, 2010
Mark went to Google
We attended the final day of DevFest 2010 at the Sydney office of Google yesterday.
Apart from acting like total tourists (with the photos and the questions and the wandering around) we actually learned some cool new stuff with the V3 Google Maps API.
Here is the result of my code lab http://flickrmap-devfest-2010.appspot.com/
Can't wait for next year !!
Apart from acting like total tourists (with the photos and the questions and the wandering around) we actually learned some cool new stuff with the V3 Google Maps API.
Here is the result of my code lab http://flickrmap-devfest-2010.appspot.com/
Can't wait for next year !!
Friday, June 18, 2010
Tomcat6 running PHP applicatoins: Can it be done?
Simply, Yes it can be done.
Download PHP-Java Bridge (http://php-java-bridge.sourceforge.net/), install it and your away.
Also, it doesn't work. It takes all day to set up the configuration and still runs pretty buggy.
By "doesn't work" I mean, to run Tomcat6 (because you already have it installed) on you windowsXP laptop to serve up PHP files straight from you eclipse workspace in order to develop and test a pure PHP app which is intended to run in a vanilla PHP production system, "doesn't work".
Why not? Well it sets the PHP session.save_path to the temp directory that Tomcat is intended to use, which is not a bad thing, except that it leaves in the single quotes. So you end up with a session.save_path of (for example) "'C:\WINDOWS\Temp'\sessions" (including the single quotes).
This then doesn't work.
You can spend half a day screwing with it but it will just end in frustration.
My suggestion.
Spend 2 minutes downloading the Apache2.2.x server MSI and then run it.
Spend another 2 minutes downloading the PHP5.x.x MSI and run it (even if you have PHP installed, rerun the installer) and select to configure with Apache2.2.
Spend 21 seconds changing the Apache Document Root to be your workspace path.
Then restart Apache.
Total for the day:
Screwing with Tomcat6 and PHP-Java Bridge - 5 hours.
Creating a fully functional dev enviroment with Apache2.2.x - 2 minutes, 21 seconds.
Download PHP-Java Bridge (http://php-java-bridge.sourceforge.net/), install it and your away.
Also, it doesn't work. It takes all day to set up the configuration and still runs pretty buggy.
By "doesn't work" I mean, to run Tomcat6 (because you already have it installed) on you windowsXP laptop to serve up PHP files straight from you eclipse workspace in order to develop and test a pure PHP app which is intended to run in a vanilla PHP production system, "doesn't work".
Why not? Well it sets the PHP session.save_path to the temp directory that Tomcat is intended to use, which is not a bad thing, except that it leaves in the single quotes. So you end up with a session.save_path of (for example) "'C:\WINDOWS\Temp'\sessions" (including the single quotes).
This then doesn't work.
You can spend half a day screwing with it but it will just end in frustration.
My suggestion.
Spend 2 minutes downloading the Apache2.2.x server MSI and then run it.
Spend another 2 minutes downloading the PHP5.x.x MSI and run it (even if you have PHP installed, rerun the installer) and select to configure with Apache2.2.
Spend 21 seconds changing the Apache Document Root to be your workspace path.
Then restart Apache.
Total for the day:
Screwing with Tomcat6 and PHP-Java Bridge - 5 hours.
Creating a fully functional dev enviroment with Apache2.2.x - 2 minutes, 21 seconds.
Subscribe to:
Posts (Atom)