Jordo Media is displaying this feed so that you can decide if you wish to subscribe to it or not. We are neither affiliated with the authors of this feed nor responsible for its content. Please report inappropriate content to via the "Report Problem" link above.
Shelley returned to the Bonneville Salt Flats last weekend for more testing. The Stanford and VW teams were focused on shaking out bugs in the driving algorithms and their map building code. This trip was also the first major trial where the Java Realtime system provided all of the GPS interfacing and data logging. The hoary old C code it replaces has been permanently and officially retired! Two systems down, with lots more to come!
I particularly like Shelley's new look with the Java logo out in front!
To hear more about the Shelley project consider attending the session S312929 : Java in the Real World: Experiences with Real-Time Java for Device Control that Marcial Hernandez of Volkswagen and I will be presenting at JavaOne 2010. We will have recent video of Shelley running on Pike's Peak and lots of details of our experiences developing Shelley and other embedded Java applications.
I've noticed that a lot of people who use the java.util Collections classes in their APIs will most often use List. Sometimes to the exclusion of the other Collections types. The other core Collections classes Set, Map and Collection are under-represented in most public Java APIs.
In the APIs I've written, especially since the introduction of generics, I try to use the other types more liberally. Why not just use List? To me List implies "ordered" and "duplicates allowed". If ordering isn't a relevant characteristic for the values I'll use Collection. If I wish to indicate that duplicate elements are not allowed I'll use Set or for cases when order does matter, SortedSet. When the collection
Using the right Collection type provides the API user a good hint as to key characteristics of the collection data. Using only List in APIs makes those characteristics less obvious and may lead to mis-use or abuse of APIs.
Last week the Oracle team which is contributing to the Volkswagen-Stanford Shelley Autonomous vehicle project reached a significant milestone: Software running on the car during trials. During Shelley's testing trials last week the car was running Java-realtime application code for handling GPS data and controlling the CAN bus. In addition to this trial being the first time that Java-realtime and OpenSolaris are running on the actual car it's also the first time that Shelley has combined key systems into a single process.
If there's one Java programming idiom I hate more than any other it's the "ignore null" idiom practiced by some Java programmers. Briefly:
Exceptionally Bad Code
public method(Foo bar) {
if(null != bar) {
// Some operation upon bar...
}
}
This is a pretty common sample. method() has special handling for bar being null. When bar is null the method has no effect. This is almost certainly evil. Unless method() considers null to be valid input and really does want to act differently based upon a null input value then choosing to ignore null inputs merely masks a problem elsewhere.
Ignoring bad input in this way ignores the principle of failing as close to the source of the problem as possible. Finding the root cause of strange behavior when the "ignore invalid inputs" idiom is used is much more difficult than when bad input causes errors. Don't be afraid of generating exceptions for bad input and/or allowing NPE exceptions to be thrown on your behalf by the JVM when called with bad input. The sooner the bad input is identified, the sooner the programmer looking at the problem can find the source of the error.
I've run into a corresponding problem in loosely coupled APIs such as web services. This is the problem where the web services API returns a 200 result no matter what input it is provided. Yes, it will provide correct results when provide the correct input but it will also happily provide (usually irrelevant) results when provided bad input. This also violates the principle of failing as soon as possible and makes problems a lot harder to diagnose. Because of the decoupling of systems this type of problem can be even harder to diagnose than the "ignoring null" problem.
Generating errors or exceptions is the correct response to your code receiving bad input. Intentionally ignoring invalid inputs is not a good strategy for any system especially when multiple programmers or modules are involved.
Like many projects the Java Store uses Maven for our build description and Hudson for our continuous integration.
We've been trying to do a bit more lately with tagging the build outputs with version and build information for later tracking. Hudson provides a number of environment variables which describe the build environment to Maven (or Ant). We're starting to use some of those variables in our output manifests and elsewhere. However, when building the projects locally the Hudson build variables aren't defined. So I came up with a little recipe which can be added to pom files to provide default values when the project isn't being built by Hudson.
The values used aren't always the best match for the values Hudson would supply but they are the closest I could come up with without adding additional requirements. For your projects you may want to tweak the values used.
Surrogate Hudson Build Variables
<profile>
<id>Hudson Surrogate Params</id>
<properties>
<env.BUILD_NUMBER>UNKNOWN</env.BUILD_NUMBER>
<env.BUILD_ID>${maven.build.timestamp}</env.BUILD_ID>
<env.JOB_NAME>${project.name}</env.JOB_NAME>
<env.BUILD_TAG>${user.name}-${env.JOB_NAME}-${project.version}_${env.BUILD_NUMBER}-${env.BUILD_ID}</env.BUILD_TAG>
<env.EXECUTOR_NUMBER>0</env.EXECUTOR_NUMBER>
<env.WORKSPACE>${basedir}</env.WORKSPACE>
<env.HUDSON_URL>UNKNOWN</env.HUDSON_URL>
<env.SVN_REVISION>rUNKNOWN</env.SVN_REVISION>
</properties>
<activation>
<property>
<!-- Activated if Hudson hasn't already set the BUILD_NUMBER -->
<name>!env.BUILD_NUMBER</name>
</property>
</activation>
</profile>
EDIT (20100429) : I have updated the sample source slightly.
I've been telling this story for the last couple of months and I thought I would share it on my blog. I volunteer with Guide Dogs for the Blind as a foster care provider. I take care of dogs that need time in a home environment. When you see me with a dog it's probably a foster care dog and likely a different dog than the last time you saw me. We've taken care of almost 50 dogs over the last two years and it's the most fun I have ever had with a volunteer job.
Recently we had the pleasure of taking care of a 7 1/2 week old puppy for about three months while she was getting old enough for some surgery and then the recovery. When we got her she was fresh from the whelping kennel and had absolutely no training. She didn't know her name, wasn't housebroken in the slightest degree, couldn't walk on a leash, etc. However, if you threw a toy she would bring it back to you ever time. Apparently retrieving is a "built-in" function for Labradors and requires no training. I was kind of amazed at how automatic retrieving was for her since she really hadn't mastered any other skills yet. The "Retriever" name is apparently well deserved.
Because I'd never be forgiven for not including a picture:
Gucci @15 weeks in the rarely seen act of sleeping with her head on a toy.
I love drinking coffee. Recently I was told to drink more coffee by my dental hygienist. Ok, so she actually told me that coffee was a better choice the the diet pop I had been habitually drinking in the afternoons and evenings. So I have been drinking lots more coffee, about 7-10 cups per day up from 3-4.
By accident I found a new way to enhance my appreciation of coffee. Some of the Halloween candy we bought this year was salty butter caramels and we have lots left over. I happened to be eating one of these caramels when I took a sip of some fresh brewed coffee. Wow! I was amazed at how eating a caramel at the same time brought out flavours from the coffee that I hadn't been able to distinguish drinking the coffee by itself. I could taste the roast much better and the specific bean flavours were much more discrete than they had been. I am not sure if it's just the salt in the caramel or something else. I tried adding cream and a bit of salt to black coffee as an experiment to see if that had the same effect but it just tasted salty and disgusting.
I'm now having fun trying all of my favourite roasts again with a caramel to see what I learn about them. I'm also finding that once my palate has been "trained" by tasting with a caramel I can pick out the same flavours without the caramel. Using a caramel seems to be an excellent training tool for coffee tasting. I am really glad I made this discovery!
The photo of Shelley in my last post was just a taste. Here's more!
This footage was taken primarily at the Bonneville salt flats in September. Notice at the end of the salt flats segment how she has drifted out the Audi logo at 95 KM/H. There's probably not very many human drivers who could drive with this accuracy. With more time Shelley could just as easily drift out a picture of Duke, the Java logo or the Mona Lisa... try that puny human!
Probably not what you thought you'd be seeing when you came to this page!
"Shelley" is the newest VW ERL test vehicle and will be conquering Pike's Peak in 2011. Yes, that's a Java logo and she is indeed "Java Powered"! Shelley will be using Java Realtime and Solaris for her driving control, GPS integration, telemetry logging and portions of her safety system.
My part, thus far, has been to provide a Solaris CAN bus driver. Which I, unfortunately, had to write in C.
As Octavian mentioned in his recent blog entry, Java Store and License Management, the Java Store will soon offer a simple license rights management system to developers. Octavain's post was based upon early work and, because there have been questions about it, I'm posting updated sample source code for the license management feature. Enjoy!
Java Store License Rights Management Sample
package com.sun.javastore.licenserightsapp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
/**
* A sample application demonstrating how to decode and verify the Java Store licensing rights object. This
* sample shows the rights code executing within the {@code main()} method that normally starts your
* application. In a real application you should move this code to wherever your application decides which
* functions are available. Note: An application can be run in demo/preview mode, in which case, none of
* the rights objects are to be set, which is an indicator to the application that it is being run in such
* mode.
*
* You may wish to use several copies of the code in different places in your
* application to check for different rights. You should try to avoid using a pattern like :
*
*
* public boolean featureUnlocked() {
* ... rights handling code ...
* }
*
*
* as this is quite simple to replace with a method that simply returns "true" all the time. The more
* you spread out the rights processing and checking within your code the harder it will be for attackers
* to disable it.
*/
public class App {
/**
* The public key which must match the key which was used for signing the rights object.
*/
private final static byte[] TRUSTED_PUBLIC_KEY = {
(byte) 0x30, (byte) 0x81, (byte) 0x9F, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A,
(byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x01,
(byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8D, (byte) 0x00, (byte) 0x30, (byte) 0x81,
(byte) 0x89, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x98, (byte) 0x21, (byte) 0xAE,
(byte) 0x6C, (byte) 0x80, (byte) 0x97, (byte) 0x6F, (byte) 0xDE, (byte) 0xAD, (byte) 0xC4, (byte) 0x59,
(byte) 0x44, (byte) 0x57, (byte) 0xCC, (byte) 0x3D, (byte) 0x7E, (byte) 0x48, (byte) 0x7B, (byte) 0xE2,
(byte) 0xEE, (byte) 0xB2, (byte) 0xA3, (byte) 0xF7, (byte) 0x53, (byte) 0x03, (byte) 0x12, (byte) 0x07,
(byte) 0x60, (byte) 0x3D, (byte) 0x5E, (byte) 0x5D, (byte) 0xEF, (byte) 0x89, (byte) 0xAF, (byte) 0xA4,
(byte) 0x6E, (byte) 0x85, (byte) 0xE3, (byte) 0xB8, (byte) 0xD1, (byte) 0xF1, (byte) 0x4D, (byte) 0x8C,
(byte) 0x8C, (byte) 0x10, (byte) 0xE5, (byte) 0x1A, (byte) 0x6F, (byte) 0x70, (byte) 0xE8, (byte) 0xAD,
(byte) 0x54, (byte) 0x96, (byte) 0xB1, (byte) 0x61, (byte) 0xC5, (byte) 0xE5, (byte) 0x42, (byte) 0x83,
(byte) 0x2B, (byte) 0xB2, (byte) 0xB1, (byte) 0x91, (byte) 0x6F, (byte) 0xB0, (byte) 0xFE, (byte) 0x0D,
(byte) 0xAF, (byte) 0x60, (byte) 0xA9, (byte) 0xD5, (byte) 0x64, (byte) 0x82, (byte) 0x8F, (byte) 0x1F,
(byte) 0xE5, (byte) 0x47, (byte) 0x45, (byte) 0x76, (byte) 0x00, (byte) 0xC1, (byte) 0x43, (byte) 0x29,
(byte) 0x10, (byte) 0x33, (byte) 0x52, (byte) 0x49, (byte) 0x53, (byte) 0x0E, (byte) 0xC8, (byte) 0xD2,
(byte) 0x98, (byte) 0x17, (byte) 0x7F, (byte) 0x6E, (byte) 0x8F, (byte) 0x41, (byte) 0x1C, (byte) 0xF6,
(byte) 0xE4, (byte) 0x6F, (byte) 0x84, (byte) 0x1C, (byte) 0x39, (byte) 0xA7, (byte) 0x17, (byte) 0x8A,
(byte) 0x31, (byte) 0x1A, (byte) 0x90, (byte) 0xD0, (byte) 0xA8, (byte) 0x44, (byte) 0x84, (byte) 0x73,
(byte) 0x01, (byte) 0x1F, (byte) 0x51, (byte) 0x19, (byte) 0x43, (byte) 0x35, (byte) 0x2D, (byte) 0x3D,
(byte) 0xC6, (byte) 0x2B, (byte) 0x68, (byte) 0x7C, (byte) 0x4F, (byte) 0x02, (byte) 0x03, (byte) 0x01,
(byte) 0x00, (byte) 0x01
};
/**
* Name of the property containing the encoded rights for this user/device/application. (BASE64)
*/
private final static String RIGHTS_BLOB_PROPERTY = "jnlp.javastore.appwrapper.rightsBlob";
/**
* Name of the property containing the digital signature of the encoded rights object. (BASE64)
*/
private final static String RIGHTS_SIGNATURE_PROPERTY = "jnlp.javastore.appwrapper.rightsSig";
/**
* Name of the property containing certificate of the signer of the encoded rights object. (BASE64)
*/
private final static String RIGHTS_CERTIFICATE_PROPERTY = "jnlp.javastore.appwrapper.rightsCert";
/**
* The ID of the user running the application as provided by the Java Store wrapper.
*/
private final static String RIGHTS_USER_ID = "jnlp.javastore.appwrapper.UserID";
/**
* The Product ID of this application as provided by the Java Store wrapper.
*/
private final static String RIGHTS_PRODUCT_ID = "jnlp.javastore.appwrapper.ProductID";
/**
* The Version ID of this application as provided by the Java Store wrapper.
*/
private final static String RIGHTS_VERSION_ID = "jnlp.javastore.appwrapper.VersionID";
/**
* The system fingerprint for this system as provided by the Java Store wrapper.
*/
private final static String RIGHTS_SYSTEM_ID = "jnlp.javastore.appwrapper.SystemID";
/**
* Clock drift window. This is padding we add in time/date calculations to allow for differences between
* the user's clock and the Java Store clock.
*/
private final static long MAX_CLOCK_DRIFT_WINDOW_MS =
/*1sec*/ 1000L *
/*1min*/ 60L *
/*1hr*/ 60L *
/*1/2day*/ 12L;
/**
* The basic right for purchased applications. If this right is absent or unavailable then the application
* is in demo mode.
*/
private final static String BASIC_PURCHASED_RIGHT = "store:run";
/**
* Main entry point.
*
* @param args command line arguments (if any).
*/
public static void main(String[] args) {
// We will decide if this application should be running in demo mode or not.
boolean demoMode = true;
try {
// Get the current time.
long now = System.currentTimeMillis();
// Recover rights info objects from system properties and decode BASE64 data.
byte[] rightsBlob = decodeBase64(System.getProperty(RIGHTS_BLOB_PROPERTY, ""));
byte[] rightsSig = decodeBase64(System.getProperty(RIGHTS_SIGNATURE_PROPERTY, ""));
byte[] rightsCert = decodeBase64(System.getProperty(RIGHTS_CERTIFICATE_PROPERTY, ""));
// Ensure that all of the rights info components are available.
if (rightsBlob.length <= 0 && rightsSig.length <= 0 && rightsCert.length <= 0) {
throw new IllegalArgumentException("Rights objects unavailable.");
}
// Read in the certificate of the signer.
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(
rightsCert));
// verify that the public key in the presented signer certificate matches the one know to trust.
if (!Arrays.equals(TRUSTED_PUBLIC_KEY, certificate.getPublicKey().getEncoded())) {
throw new IllegalArgumentException("Incorrect signer.");
}
// Verify the signature using the certificate against the rights info blob.
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(certificate);
signature.update(rightsBlob);
if (!signature.verify(rightsSig)) {
throw new IllegalArgumentException("Signature doesn't match.");
}
// We can now trust that the rights info blob is authentic.
// The rest of the processing is devoted to using the rights info.
// Read a Properties map from the rights info blob.
Properties rights = new Properties();
rights.load(new ByteArrayInputStream(rightsBlob));
// Extract some values from the properties map
// The ID of the product to which the rights are applied.
int productId = Integer.parseInt(rights.getProperty("productId", "-1"));
rights.remove("productId");
// The ID of the user holding the rights.
int userId = Integer.parseInt(rights.getProperty("userId", "-1"));
rights.remove("userId");
int systemId = Integer.parseInt(rights.getProperty("systemId", "-1"));
rights.remove("systemId");
// The ID of the device on which the application is running.
String deviceId = rights.getProperty("deviceId", "");
rights.remove("deviceId");
// Timestamp at which this rights info was generated in milliseconds since Midnight Jan 1, 1970 UTC ("the epoch").
long timestamp = Long.parseLong(rights.getProperty("timestamp"));
rights.remove("timestamp");
// Print out the core properties of the rights info.
System.out.printf("product : %d user : %d system : %d device : '%s' timestamp : %s \n",
productId, userId, systemId, deviceId, new Date(timestamp));
// Perform checks upon the properties.
// The product ID must be a positive number.
int appProductId = Integer.parseInt(System.getProperty(RIGHTS_PRODUCT_ID, "-99"));
if (productId != appProductId) {
throw new IllegalArgumentException("Invalid product Id");
}
// Normally the userID is > 0. If the userID is -1 then this is a preview or demo and we should
// not expect any rights.
int currentUserId = Integer.parseInt(System.getProperty(RIGHTS_USER_ID, "-99"));
if (userId != currentUserId) {
throw new IllegalArgumentException("Invalid user Id");
}
// The ID of the system on which the application is running.
int currentSystemId = Integer.parseInt(System.getProperty(RIGHTS_SYSTEM_ID, "0"));
if (systemId != currentSystemId) {
throw new IllegalArgumentException("Non-matching system Id");
}
// Device ID must be present. This is used to track how many devices the user is installing the
// application on.
if (0 == deviceId.trim().length()) {
throw new IllegalArgumentException("Invalid device Id");
}
// Compare timestamp to current time allowing for clock drift.
if ((timestamp < 0) || (now - timestamp < -MAX_CLOCK_DRIFT_WINDOW_MS)) {
throw new IllegalArgumentException("Invalid time stamp");
}
if (!rights.isEmpty()) {
System.out.println();
}
// At this point all remaining keys in the rights map should be single right descriptors.
if ((-1 == userId) && !rights.isEmpty()) {
System.out.printf("*** Rights Info should be empty when in demo/preview mode.\n\n");
}
// Print out properties for each right in the rights info.
for (Map.Entry
And a unit test which invokes the sample code.
Java Store License Rights Unit Test
package com.sun.javastore.licenserightsapp;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase {
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest(String testName) {
super(testName);
}
/**
* @return the suite of tests being tested
*/
public static Test suite() {
return new TestSuite(AppTest.class);
}
/**
* Rigourous Test :-)
*/
public void testApp() {
String SAMPLE_RIGHTS_BLOB =
"I1dlZCBTZXAgMTYgMTc6MzM6NDQgUERUIDIwMDkKc3lzdGVtSWQ9MzU5Nzg3MQpyaWdodC4yPUkx" +
"ZGxaQ0JUWlhBZ01UWWdNVGM2TXpNNk5EUWdVRVJVSURJd01Ea0taWGh3YVhKaGRHbHZiajB4TWpV" +
"ek1UVXhNakV5TkRFNENtNWhiV1U5YzNSdmNtVmNPbk4xWW5OamNtbHdkR2x2YmdwcGMwZHlZVzUw" +
"WldROWRISjFaUXB5WldObGFYQjBTV1E5TWdwd1lYbHRaVzUwVkhKaGJuTmhZM1JwYjI1SlpEMHhN" +
"alFLWVdOMGFYWmhkR2x2YmoweE1qVXpNVFEzTmpFeU5ERTRDbkJoZVcxbGJuUlFjbTlqWlhOemIz" +
"STlVR0Y1VUdGc1FWQUsKcmlnaHQuMT1JMWRsWkNCVFpYQWdNVFlnTVRjNk16TTZORFFnVUVSVUlE" +
"SXdNRGtLYm1GdFpUMXpkRzl5WlZ3NmNuVnVDbWx6UjNKaGJuUmxaRDEwY25WbENuSmxZMlZwY0hS" +
"SlpEMHhDbkJoZVcxbGJuUlVjbUZ1YzJGamRHbHZia2xrUFRFeU13cHdZWGx0Wlc1MFVISnZZMlZ6" +
"YzI5eVBWQmhlVkJoYkVGUUNnXD1cPQp1c2VySWQ9MQpwcm9kdWN0SWQ9Mwp0aW1lc3RhbXA9MTI1" +
"MzE0NzYyNDYwMwpkZXZpY2VJZD05MzIxRTAyMy1DRUEyLTQxQTItODM1Mi1ERUVFODYxMDA4OEMK";
String SAMPLE_RIGHTS_SIG =
"GHNXWheMgBv8NC/jR9rVuwufyLgtirKsFq7C8dWL4Uzb4+3pZmfoqNLrxbXiTErCP4F42UnkP8mF" +
"i8sFsdO99xGCuaa1zQqZO9zXNScKBxzRlKcSuzIRDynnq0CN9Wz82ibeA+b5S7HpsQ7nUbHb6SEu" +
"9BqjArTEc8wu7RCcTZo=";
String SAMPLE_RIGHTS_CERT =
"MIIE5jCCA86gAwIBAgIQXqXlgX7rylXBGhLidL9EhzANBgkqhkiG9w0BAQUFADCBgzEdMBsGA1UE" +
"ChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsx" +
"JTAjBgNVBAsTHENsYXNzIDIgT25TaXRlIFN1YnNjcmliZXIgQ0ExGjAYBgNVBAMTEU9iamVjdCBT" +
"aWduaW5nIENBMB4XDTA5MDgyNzAwMDAwMFoXDTEyMDgyNjIzNTk1OVowbTEdMBsGA1UEChQUU3Vu" +
"IE1pY3Jvc3lzdGVtcyBJbmMxITAfBgNVBAsUGENvcnBvcmF0ZSBPYmplY3QgU2lnbmluZzEQMA4G" +
"A1UECxQHQ2xhc3MgQzEXMBUGA1UEAxQOU3VuIEphdmEgU3RvcmUwgZ8wDQYJKoZIhvcNAQEBBQAD" +
"gY0AMIGJAoGBAJghrmyAl2/ercRZRFfMPX5Ie+LusqP3UwMSB2A9Xl3via+kboXjuNHxTYyMEOUa" +
"b3DorVSWsWHF5UKDK7KxkW+w/g2vYKnVZIKPH+VHRXYAwUMpEDNSSVMOyNKYF39uj0Ec9uRvhBw5" +
"pxeKMRqQ0KhEhHMBH1EZQzUtPcYraHxPAgMBAAGjggHtMIIB6TAJBgNVHRMEAjAAMA4GA1UdDwEB" +
"/wQEAwIHgDBrBgNVHR8EZDBiMGCgXqBchlpodHRwOi8vb25zaXRlY3JsLnZlcmlzaWduLmNvbS9T" +
"dW5NaWNyb3N5c3RlbXNJbmNDb3Jwb3JhdGVPYmplY3RTaWduaW5nQ2xhc3NDL0xhdGVzdENSTC5j" +
"cmwwHwYDVR0jBBgwFoAUs0crgn5TtHPKuLsZt76BTQeVx+0wHQYDVR0OBBYEFJHwpfEC3ziinvN3" +
"8dKlgVR5OrW1MDsGCCsGAQUFBwEBBC8wLTArBggrBgEFBQcwAYYfaHR0cDovL29uc2l0ZS1vY3Nw" +
"LnZlcmlzaWduLmNvbTCBuQYDVR0gBIGxMIGuMDkGC2CGSAGG+EUBBxcCMCowKAYIKwYBBQUHAgEW" +
"HGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwcQYLYIZIAYb3AIN9nD8wYjAnBggrBgEFBQcC" +
"ARYbaHR0cHM6Ly93d3cuc3VuLmNvbS9wa2kvY3BzMDcGCCsGAQUFBwICMCsWKU5vdCBWYWxpZGF0" +
"ZWQgRm9yIFN1biBCdXNpbmVzcyBPcGVyYXRpb25zMBEGCWCGSAGG+EIBAQQEAwIEEDATBgNVHSUE" +
"DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQUFAAOCAQEAPoQ8RWJ6xfnY8YxHL3kEVEPxKyDAa+sG" +
"Ng5Rw2SaXFek9KMfMvU6DUXdj/BYIuLu9S2cVIHlIyFINzT6gtxsDNTkByMmRys8lsCZhXv767Pe" +
"b/KW2sZWA8fxSE6JDRpWsE7j4PSr3rBB6YNqCTX0qH5yzumx2Lfk28BILKW7ri4cmakaql+Vi+6q" +
"QIqhxDu1FzAdbwp/DzAJYtafcAZa381jDH3kwpSXpP15V1jqZgGYs387hQEYDWie4J5sol7g0cN9" +
"zlRZQMxwU6Rcz/nWiM24mGB/W0NH7ggMS7/AWz6efN534OAxgWuBA96Qwf7TWKdZWzWEdhZar483" +
"hfmZiw==";
System.setProperty("jnlp.javastore.appwrapper.UserID", "1");
System.setProperty("jnlp.javastore.appwrapper.ProductID", "3");
System.setProperty("jnlp.javastore.appwrapper.VersionID", "3");
// This value will be calculated by the java store runtime.
int systemId = "user".hashCode() ^ "os".hashCode();
System.setProperty("jnlp.javastore.appwrapper.SystemID", Integer.toString(systemId));
System.setProperty("jnlp.javastore.appwrapper.rightsBlob", SAMPLE_RIGHTS_BLOB);
System.setProperty("jnlp.javastore.appwrapper.rightsSig", SAMPLE_RIGHTS_SIG);
System.setProperty("jnlp.javastore.appwrapper.rightsCert", SAMPLE_RIGHTS_CERT);
App.main(new String[0]);
}
}
The Two Words : Some relevant advice regarding legacy technology from Bob Newhart.
I've been compiling a list for the last couple of months of legacy technologies that I feel are well past their 'Best Before Date' and should be eliminated. Keeping them around in spite of better alternatives makes all of our jobs more complicated. The reasons for keeping the dead technologies alive end up sounding like delusional rationalizations.
I'm looking for suggestions of obsolete technologies which we would all be better off by getting rid of them. I'm not going to share the complete list I've compiled because I want people to come up with their suggestions. Some ideas to get you started:
Cylinder/Head/Sector Disk Addressing
Telnet/rsh/rlogin
Non-UTF character encodings
S-Video
...
If there's a technology you're forced to use or support that's best destined for the boneyard please make the case for its obsolescence.
With Solaris 10u8 aka Solaris 10 10/09 due any day now I've been planning to upgrade my installations. When I originally installed Solaris 10u6 with ZFS boot I assumed that the upgrade process to 10u7 would be about the same as it has been for UFS boot installations. It turns out, unfortunately, that the Solaris 10 installer doesn't offer direct upgrades for ZFS.
After a few days of fruitlessly searching the Internet for a procedure to upgrade my ZFS boot installation from 10u6 to 10u7 I contacted my Solaris oracle, Dave Clack and, of course he knew exactly how to do it. Since lots of people will undoubtedly need this procedure in the next couple of weeks, here it is. This procedure also works for OpenSolaris. Dave's instructions mount the DVD ISO using lofi loopback. If, like me, you are running you Solaris installations in VirtualBox then you can just mount the image as a virtual DVD. The procedure remains the same with a few path changes.
Upgrade a Solaris 10 ZFS Boot Installation from one "u" level to another
lofiadm -a /share/iso/solaris_dvd.iso
mount -F hsfs /dev/lofi/1 /mnt
pkgrm SUNWlur SUNWluu SUNWluzone SUNWlucfg
cd /mnt/Solaris_10/Product
pkgadd -d . SUNWlucfg SUNWlur SUNWluu SUNWluzone
10uX is currently installed version
10uY is the version number of the one you downloaded
lucreate -c 10uX -n 10uY
lustatus
luupgrade -u -n 10uY -s /mnt
luactivate 10uY
init 6
I had "that argument" with someone again recently. You know, the one about Java performance vs. C code. It's an argument I am very tired of having and I'm tempted to go "Barney Frank" on the next person to suggest there's a difference that matters.
One of the supposed C advantages is supposed to be that it offers greater opportunity for optimization. Maybe I have been looking at the wrong code lately but I see very little code these days that instruction-wise optimization, inline assembly or hand tweaking makes better. The biggest problem is not that careful optimization of small functions doesn't produce speed improvements but that those speed improvements are, overall, of marginal benefit. Here's some really bad code:
StinkoCode.java
static void main(String[] args) {
List sortedArgs = new LinkedList();
for(String arg : args) {
sortedArgs.add(arg);
Collections.sort(sortedArgs);
}
System.out.println(sortedArgs);
}
Even though this is just a contrived example, yes, I do regularly see code this inefficient. Would optimizing the sort() operation have much impact on the overall behaviour of this program? How about the choice of LinkedList? Would using a bulk insertion strategy such as addAll() help? If there are many arguments passed in the biggest gains would almost certainly come from sorting the arguments only once and possibly using a different data structure to store the strings. Let's try that again:
As cautions against premature optimization suggest, is critical to carefully examine the causes your hot code is burning so many cycles before optimizing. Frequently the real problem is with the calling code and not the exact piece of code which shows up in the profiler as your hot spot. When planning optimizations it's usually best to look "up the stack" and evaluate the usage pattern for the bottleneck code being called before diving in to make a targeted fix. Most likely, at best, you'll only get a marginal improvement by making a local optimization. For the really big wins you should be focusing on the higher order causes.
Cocktail sauce, lemon, Tabasco, Tapatio, mignonette... all are commonly offered as accompaniments to raw oysters. I say phooey to them all. A good raw oyster is perfect just by itself. Well almost... a fine Sazerac cocktail and oysters are a great combination.
Tom Waits has always refused to have his music used in commercials. He has successfully sued those who have used his music without his authorization and also successfully sued companies who used sound-alike songs or singers. Reading about these lawsuits on Wikipedia a couple of years ago I felt that he was certainly within his rights to control how his music is used but he was perhaps a bit too hardline about restricting their use. Look what "Bombastic" did for Shaggy, etc. Having enjoyed Tom's music for more than 25 years I wish more people knew his music. Commercials seemed to me to be a fine way introduce people.
A couple of weeks ago I heard Tom Waits' distinctive voice over a commercial on Hulu and immediately drew my attention because it was entirely unexpected. The commercial is a PSA for Feeding America. I now understand why Tom has chosen not to dilute the effect he gives the commercial by also shilling for Pepsi and Chrysler.
In the deep dark past there was this one commercial for Purina though. I find his intonation hilarious.
You want to know how to frustrate a web accessibility architect? Suggest you are adding alt tags to your images for the SEO benefits rather than for accessibility. It's true that image alt tags do increase page search rankings and the resulting tags are useful for those using non-visual browsers, but wasn't making your pages accessible reason enough?
If that doesn't work you can suggest that you'll continue to use tables for formatting even after you convert to CSS or include multiple invisible iframes on every page.
A few months ago I was updating my Wikipedia user page after seeing a user box on someone else's user page that I wanted on my own user page. I opted to browse a bit and see if there were other boxes that I might also want to add.
One category of user box I wished to add to my page was to indicate my language preferences. Though I live and work in the United States I've remained a devout Canadian speller and used other idioms of Canadian writing (garbage not trash, holiday not vacation, etc.). Confronted with the options for spelling preferences I found that there was no existing user box for "I use Canadian spellings". I didn't wish to use the "I prefer United Kingdom spelling" user box because I don't use UK spellings for many words. I could have originated a new "Canadian spellings" user box but another of the existing choices intrigued me:
This polyorthographic user box doesn't accurately describe how I try to write. I do prefer to write using Canadian spellings and idioms, but it does reflect how I read. I'm comfortable reading almost all modern styles of written English. I opted to add this user box to my Wikipedia user page rather than creating a new Canadian English user box. I didn't feel that it was entirely accurate but felt the distinction wasn't worth fussing over.
Since adding the user box I've actually continued to think about it and how I use language, strange as that may sound. I discovered that my feelings about using Canadian style orthography were more complicated that I had thought. For example, last year while working on the JXSE Programmers Guide 2.5 I made the conscious decision to use American spelling and grammar to be consistent with the previous edition and the other chapters written by other people. Reasonable enough. Also, after reading about International English, Basic English, E-Prime and the Simplified Spelling Society (all courtesy of the zany link boffins at reddit.com) I decided to follow some of the rules that these simplified grammars advocate for my email and forum communications whenever I suspected that the reader might not be a native English speaker. I believe that using English that is less idiomatic has possibly made my writing easier to understand. Since I can never remember all of the English grammar rules anyway I'm also choosing to write only in the narrower style of the rules that I do know.
I'm finding myself becoming increasingly comfortable with being a polyorthographic English writer and now believe that the user box will eventually accurately reflect my writing. I'm also taking more of an interest in other ways I can continue to improve my written English.
The Consumerist is linking today to the innovative and pleasantly refreshing AviaryTerms of Service page. Wow! Why can't they all be like that?
I still convinced that the terms could be even shorter and less legally dense. (legal density--good or bad--discuss amongst yourselves).
I'm getting really tired of every single website having it's own password policies. I'm sure everyone else is as well. About 10 years ago there was an effort by authors of Usenet client applications to develop a Good Netkeeping Seal of Approval. The practices it describes are intentionally minimal. The GNKSA doesn't specify how to write a Usenet reader but it does specify many important details that every client should follow.
This type of best practices effort for Internet applications is required now more than ever. It is incredibly frustrating that nearly every site and (ahem!) even different sites by the same company has a different policy for managing details such as permitted and acceptable passwords, account and password recovery mechanisms, email change policy, etc.
I have been doing a lot of work using virtual machines (the simulates-a-computer kind not the Java kind). Since all of the virtual systems are NATed or have no networking and because I'm mostly doing driver development I am generally logged in as root and not using a password. Obviously, this has usage and security implications. For one thing, I can't assume that there is any kind of safety protection. If I screw up then the machine is screwed up. This applies to the security as well. If I do something stupid like download random software or go to arbitrary web sites then I could easily screw up the virtual machine.
So far I haven't managed to corrupt, infect or otherwise damage any of my virtual machines. I've found it kind of interesting how the direct knowledge that I have no "safety net" when operating these machines has impacted my thinking and choices. I've found I am a lot more thoughtful and cautious about the actions I take. I spend more time considering implications before hitting return. I'm coming to think that perhaps working in this way is possibly a good thing. Having to be certain before committing to actions has actually saved me time. I've made fewer repairable mistakes and frequently changed my mind as to how to correctly proceed rather than just barging ahead.
The moral of the story is (as usual) make good backups, play safe and be brave.
I noticed another site, the Daily Beast, is now offering a "View as Single Page" link for their longer articles. Nice. Thanks. The Christian Science Monitor and New York Times also offer a "Single Page" link for most of their content. I have to ask though, why would anyone assume that I'd prefer the multiple page layout? I understand completely that breaking an article into multiple pages increases your advertisement impressions but is it really worth annoying your readers that much?
The worst sites are invariably computer gaming review sites. It's not uncommon to see 20 "page" articles (and sometimes with no way to jump ahead or Table of Contents). Given that the ads they are showing are generally the least profitable Adwords terms and they have no other sources of revenue it's perhaps understandable that they julienne their articles.
If print media is going to successfully transition from paper to online then making their product easy and pleasant to access has got to be more of a priority.
Many people are still ruining the holiday season by serving their family and friends the dreaded cranberry cylinder:
This holiday disaster can be averted by preparing your own much tastier cranberry sauce from scratch.
Simple Cranberry Sauce Recipe
1lb/500g bag of fresh or frozen cranberries
1.5 cups of orange juice (approx).
1.5 cups of red port wine (approx).
dash of salt
2 cinnamon sticks
1 cup of sugar (approx./to taste)
zest of one orange or lemon (optional)
Ingredient notes
If cranberries are fresh then put them in the freezer overnight. Freezing
breaks the cell walls and they cook more quickly. I used to buy fresh
berries but now just buy frozen if they are available. Unless the berries
are really old and have "freezer funk" you won't be able to tell the
difference.
I use frozen or "from concentrate" orange juice. Fresh orange juice is
wasted on this recipe.
You must use a very cheap port for this recipe. If it doesn't have a screw
cap, you're doing it wrong! Cheap port has the right mix of acidity, sugar
and grapeiness to balance it's otherwise awful taste. The subtle, refined
good taste of fine port can't stand up to the rest of the flavours in this
recipe. You must use wino port.
The cranberries, juice and port all have varying amounts of sugar so you
have to adjust the sugar to your taste. As the sauce cools it will taste
less sweet.
Directions
Put frozen berries into a bowl of water big enough so that they float. Pick
out anything you wouldn't want to eat. This includes green berries, moldy
berries, dry shrivelled berries, leaves, sticks, dirt, etc.
Transfer cleaned berries to a small pot. The pot should be about half full
with the berries in it. Add orange juice and port in equal measure until
some of the berries just begin to float. Add the cinnamon stick, salt and
optional citrus zest.
Bring to a boil over medium heat. Reduce heat to low and simmer for about 2
hours stirring every half hour. When most of the berries have lost their
shape the sauce is done cooking. Turn off the heat and allow sauce to cool
for 15 minutes. The sauce will thicken and gel as it cools.
Stir in the sugar a couple of tablespoons at a time tasting after each
addition to see if the sauce is sweet enough. Sauce can be served warm or
can be chilled before serving in the refrigerator.
I really like the new CBC Radio One show The Point. It's a breath of fresh air to hear from viewpoints that aren't defined and chosen solely by political affiliation. It's also a lot more interesting. So far the selection of guests has delivered some really smart, incisive, surprising and informative discussion. And it's not ever been strident, ignorant or boring. Great stuff!
About four years ago I wrote an entry about Jacques Pepin's memoir as a chef, The Apprentice. This morning Jacques was a guest on KQED Forum and I got to ask one of the questions I had about his memoir.
Reading the memoir, his transition between working in France and his move to the US had seemed abrupt and unexplained. So I asked, "Why did you move to America?" (at about 43:45 into the podcast). His answer, which is also in the podcast, was essentially that he came to America to learn English and see the place for a year or two. He didn't really plan to stay, but found he loved New York and chose to make America his home.
It was really great to speak to Jacques and get my question answered!
Less than 5 minutes later a friend called with the obligatory, "Holy crap! You were on Forum!" call. It was nice to know someone noticed!
I'm working with a new code base and a new build process for a small project I am working on. The project makes use of the 'jstyle' code style checker tool. I've been running seriously afoul of it's rules by having the timidity to leave extra whitespace at the end of lines and add extra whitespace in expressions.
I've complained before about overly rigorous coding standards but the "remove your extra whitespace" insistence is driving me nuts. I'm sorry, I just don't care. My editor puts in whitespace to make aligning text easier. I can't see whitespace and I normally don't scour my source to make sure that my editor hasn't added any. Since the compiler doesn't care, why complain about it? (I also happen to like using "flowed" format for Javadoc with the hope someday that my text editor will free me from having to do line
wrapping manually within documentation comments).
There's a lot of stuff that just doesn't matter. There's a limit to how much "extra" energy people have for "doing the right thing". Being pedantic about minor issues depletes that energy without accomplishing much.
By special request I made cooked vanilla pudding from scratch last night. I've made custard from scratch before but this was the first time I've made pudding without a box. Here's the recipe I used: Vanilla Pudding Recipe.
As you can see the recipe isn't that difficult. It's not much harder than preparing packaged cooked pudding and it doesn't require any special ingredients. The result was quite good though perhaps a little sweet to my taste. It also wasn't perfectly consistent though I didn't stir it after chilling before serving. Having made scratch cooked pudding I now can't imagine buying boxed pudding again as it seems like a waste of money. Next time I'm going to try caramel pudding.
Calling number identification is definitely a mixed blessing. I missed a call today while making my lunch. The call appears on my phone's display as being from the Sun main switchboard number. This mean that the call could be either an external call which was forwarded to my direct line by an operator or the automated attendant or it could be a call from another Sun employee. Unfortunately I'll probably never know who tried to call me. Whoever it was didn't leave a message and I can't call them back. I think I'd feel happier if I didn't know that I had missed the call. When I can't sleep tonight agonizing over who it was that called I will be cursing Theodore Paraskevakos, the inventor of caller ID.
My copy of the recently published, Practical JXTA, arrived the other day. I have been thumbing through it during compiles. I haven't yet had time to read in detail more than the introduction, table of contents and the author bio.
Looking at the table of contents it appears that the book hits exactly the points that have traditionally (or recently) caused developers confusion and pain as they are learning JXTA. It also really helps that the book is based upon the latest JXSE 2.5 release. Some of the code shown in older books no longer compiles properly with the latest releases (and some of it I'm pretty sure never compiled). JXTA has evolved and improved a lot over the years and without new editions the older JXTA books, or at least their code examples, have become obsolete. Learning JXTA with a new up-to-date book should be a lot easier.
I'm looking forward to reading the entire book when I get the time.
The logos and trademarks used on this site are the property of their respective owners.
We are not responsible for comments and contributions (photos, downloads, etc) posted by our users, as they are the property of the poster