OS X 10.10 Yosemite, RVM und MacPorts/HomeBrew

Nach dem Update auf Yosemite funktionieren die bisher installierten Rubies via RVM nicht mehr, und man muss diese neu installieren. Schlimmer noch, das dies aber nicht so ohne weiteres geht.

Legen wir los.

1. Aktuelles Xcode

Nach der Installation sollte man das aktuelle Xcode 6.1 installieren. Das ist aktuell noch nicht via MAS (Mac App Store) verfügbar, liegt aber im Apple Developer Center zur Verfügung.

Angeblich reichen mittlerweile auch die Command Line Utils, das habe ich nicht ausprobiert. (Xcode bietet ja auch den iOS Simulator, daher ganz praktisch…)

Gegebenenfalls muss man den MAS nochmals aufsuchen und die Updates prüfen. Bei mir erschienen da Folge-Updates für Xcode; die hießen zwar Command Line Utils, waren es aber scheinbar nicht?!

2. Command Line Utils

In dem Terminal kann man mit xcode-select –install dafür sorgen, dass die Verfügbarkeit der Command Line Utils gewährleistet ist. Falls nicht, dann den kommenden Dialog bejahen und warten.

3.1 MacPorts

Falls die MacPorts vor dem Update installiert waren, dann muss man eine Migration durchführen (einfach port ausführen, dann erhält man den Hinweis). Falls man nicht unbedingt die alten Ports braucht (man installiert sich die notwendigen dann eh neu), dann kann man auch einfach alle weg schmeißen: (a) Einfach die neuen MacPorts via macports.org runterladen und neu installieren, dann (b) alle deinstallieren mit sudo port -f uninstall installed und anschließend (c) alles Informationen löschen sudo port clean all ausführen. Die letzten beiden Schritte dauern ein paar Minuten.

3.2 HomeBrew

Falls HomeBrew installiert war, dann hier schauen, aber das sollte man sich überlegen. Ich würde da im Zweifel auch eher einen Kahlschlag machen. Man hat da eh meistens in der Vergangenheit Dinge installiert, die man gar nicht mehr braucht.

4 RVM

Wir brauchen auf jeden Fall die neuste Version: rvm get stable

Bei mir hat RVM bei einem Upgrade die Autolibs (also den zu verwendenen Default Package Manager) von MacPorts zu HomeBrew gewechselt, daher muss man ggf. rvm autolibs macports ausführen. (Hinweis: Das gilt ab sofort, das heißt bereits offene Shells laufen noch mit der alten Einstellung!)

Da bereits Rubies und Gemsets vorhanden sein werden, sollte man diese alle entfernen (sie linken teilweise auf nicht mehr korrekte Ports/Brews): rvm remove all

Auch löschen wir alle lokalen Informationen: rvm cleanup all

4.1 RVM und apple-gcc42

Sowohl die Variante über MacPorts als auch HomeBrew stolpern aktuell bei der Installation von älteren Rubyversionen über den Compiler apple-gcc42. Beide wollen diesen installieren, aber das funktioniert nicht (mehr?) unter OS X 10.10 / Darwin 14.

Allerdings braucht das Kompilieren von Ruby nicht zwangsläufig GCC, sondern läuft auch mit clang: rvm install 1.9.3 –with-gcc=clang läuft wunderbar — sowohl unter MacPorts als auch HomeBrew. Beim aktuellen Ruby 2.1.3 ist das nicht mehr notwendig.

5. RVM Autoinstall

Unter Berücksichtigung von Projekten mit alten Rubies (siehe Schritt 4.1), funktioniert jetzt die automatische Installation von Ruby, Gemset und deren Path-Aktivierung auch für Gemfile. Die ~/.rvmrc benötigt dafür ja nur:

rvm_install_on_use_flag=1
rvm_autoinstall_bundler_flag=1
rvm_gemset_create_on_use_flag=1

Broken Java Key&Trust Store on OSX

Sometimes Java applications do not find the internal Key- and Truststore (where all well known SSL roots are listed). Last one was Minecraft on OS X 10.9 with installed JRE6, JDK7 and JDK8. Even a pre-defined $JAVA_HOME did not help.

javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

Hopefully, this fix should help you. 

# Sometimes some Java applications will not work because the internal references to the trusted libs are broken.
# Unless '/System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security' does not exist, this should help
$ sudo mkdir -p /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security
$ cd /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security
$ sudo ln -s /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/security/cacerts
$ sudo ln -s /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/security/blacklist
$ sudo ln -s /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/security/trusted.libraries

Wege eines IP-Pakets

Habe gerade eine E-Mail aus Neuseeland bekommen, und das mal zum Anlass genommen, den IP-Weg zu verfolgen. Wahrscheinlich wenig überraschend geht der Weg über Amerika (über die Ozeane einfacher).traceroute-nz

 

Ausgehend von NetCologne scheint es wohl eine Direkt-Uplink zum Amsterdamer Einstieg (6. -> 7.) des Backbone Betreibers Hurricane Eletric (he.net und hier gibt es eine Karte der Locations) geben, und gleichzeitig verlässt das Paket HE auch erst wieder auf der anderen Seite des Globus (12. -> 13.) — Vocus Communications (www.vocus.com.au) ist ein australischer Provider. Anschließend wird das Paket einem Nummernkreis von Vodafone Neuseeland übergeben (via infobyip.com).

Innerhalb der Backbone von HE ist es aber spannender, denn hier geht natürlich einerseits die größte Strecke, andererseits auch der größte Delay verloren. Die Standorte dürften sich an den Servernamen ablesen: ams1 Amsterdam, lon2 London, nyc4 Ney York, sjc2 Singapur.

So ist der Ping sowohl nach Amsterdam (7.) als auch London (8.) unscheinbar (20-25 ms), aber der Sprung über den Atlantik nach New York (9.) macht sich mit zusätzlichen 70 ms dann doch bemerkbar. Das ist jedoch nichts zu dem nächsten unmittelbaren Sprung (Nebendetail: es gibt scheinbar keinen Sprung an die Westküste der USA?) nach Singapur (10.), der ganze 70 ms dazu bringt. Darüber hinaus reduziert sich die verfügbare Interconnection-Transit-Bandbreite auf 10 Gigabit.

Während die Übergabe Singapur nach Australien (Vocus) dennoch einen kaum nennenswerten Verlust mit sich bringt, hat der letzte Sprung von Australien nach Neuseeland es dann in sich: zu den vorhanden 160ms kommen nochmals ganze 120 ms dazu (insgesamt also rund 280 ms).

Consume a remote Java method with AMQP using Spring Integration

After the unexpected interest about exposing a method (thank you Josh mentioning it in the weekly news) , I will go ahead. Let’s consume such a service we had exposed.

Remember: We had a service method which is integrated via an AMQP queue (in my case RabbitMQ, but you can change this into whatever you want). That means the consumer only have to connect itself against this queue and have to send and receive suitable objects in JSON.

Consuming a method with AMQP using Spring Integration

We use the same example like in “Expose a Java method with AMQP using Spring Integration”, but from the consumer perspective.

We will put the cart before the horse and start with the AMQP setup. Instead of the inbound-gateway we have to use the outbound-gateway. Well, the name  is self-explanatory. An outbound gateway integrates a channel (requestChannel) with an external service (here AMQP). And because it is a gateway, it will handle the reply message as well (put into resultChannel).

Now we could bind the channels with some Spring Integration? Well, we must not forget the messages are transported in JSON. Said this, we have to ensure the message are transformed from and to JSON correctly before connecting them with the rest.

Both transformers intercept the messages. The result are two channels (requestChannel and resultChannel) which are for the service; the other two channels are only for serializing and deserializing. Okay, let’s go.

and

That’s it.

Wait, what?! Yep.

We have already both channels (one for outgoing invocations, one for the return values). The rest is more or less boiler code, so you can use one of the built-in gateway proxies provided by Spring Integration. The Spring Integration <int:gateway> builds a proxy object for the given interface and do the “magic” integration with the Spring Integration message flow. including waiting for the reply. You should have remember the @Payload annotation which is the same as on receiver side.

For each “call” onto MyGateway.handle(Request):

  1. the proxy creates a new Spring Integration message containing the object “request” as payload and put it into the channel “requestChannel” defined in the configuration;
  2. the message will be transformed into JSON, and will be put into requestChannelJson;
  3. the message will be transmitted via AMQP (just another gateway actually) and waiting for a reply;
  4. the reply message will be received and put into resultChannelJson;
  5. the message will be transformed from JSON into a POJO and put into resultChannel;
  6. the message finally receives the waiting gateway and returns the reply like a regular method

Because this can take some time and would block the current thread, you can (better: should) use futures. The gateway proxy will take care of this!

 

 

 

Expose a Java method with AMQP using Spring Integration

The goal for this article: expose a method of a bean via AMQP and use JSON as a unified transport which can be serialized and deserialized in every language (and forget the xml overhead, of course).

Disclaimer: All examples are cleaned up and being reduced of irrelevant boiler code like for demo-purpose unnecessary xml headers.

Let’s start with an implementation:

Both Request and Response are good old plain Java objects with can easy serialized and deserialized. Excited about Joda? I’ve written something about it!

If we want to expose that one, we first have to connect this with Spring Integration. Speaking of Spring Integration, that means basically connecting something (i.e. a method) with a channel which is the instrument of message flows in Integration. Well, that means actually integrating stuff. Not a freely chosen name? :)

For configuration purpose, you can use both JavaConfig and XML. However, while JavaConfig is more confidently usable with parameters, especially the Integration configuration is sometimes more readable in XML. Chose your own way, but be consistent. Mixing up configurations is a no-brainer.

First of all, we have to define two channels. One for incoming messages (the actual argument of the method invocation), another one for outgoing messages (the return value).

Because we want to invoke a service on a message, we simply use a ServiceActivator. For each message in the requestChannel, it will be invoked.

and

So far, each message in requestChannel will be an invocation of ApiImpl. The additions in the class defines which method should be invoked and which message argument should be extracted from the payload (you could use the actual Integration Message object, but we stick with the payload). The return result will be pushed wrapped into a message again into the defined output channel resultChannel.

The method is now well “integrated”.

Said this, we want to connect the channels with an AMQP server in order to handle incoming requests and process them. Then plan is simple: For each message at a specific queue, we create a message and put it into a channel and wait for a corresponding reply message on another channel to make a real “reply behavior”. The whole stuff is already implemented and built-in available in Spring Integration AMQP.

For example, you have a queue named queue (hell, yes).

And that.. that was it? Well, actually we have reached the goal of connection already. We have defined an inbound gateway (read: get all messages and put them into a channel and do this for the returning result vice versa) and connect all channels. Basically, this works. However, this means that the message’s payload will be transmitted with a standard serializer and deserializer which means Java Object serializing. That is not good between different components or even the non Java world.

Solving this issue means introducing some neat transformers. A transformer is nothing less than a mapper converting objects from one type to another. In our case, we want to transport the objects via JSON. So: Read JSON from AMQP, deserialize it back to a POJO, process the message, return a value and serialize it to JSON and finally send it back via AMQP.

We add two more channels which are being the new connection points for the AMQP endpoint: both requestChannelJson and resultChannelJson will be feeded with JSON messages.

As you see, the built-in directives defines that all messages of requestChannelJson will be transformed to a POJO and put into requestChannel. The same way back for the result channels. Finally, we have to adjust the AMQP configuration to use the new Json channels. That’s it.

Migration Spring Integration 2.x to 3.x with Jackson2 and Joda DateTime

Until Spring Integration 3 finally introduced built-in support for Jackson2, you are probably sticked at Jackson 1 (1.6 or so) for messaging serialization, i.e. used for AMQP endpoints like RabbitMQ. That was even more ugly in web projects where the complete MVC stack was Jackson2 ready, but not the integration part. Even though that situation is unattractive, you could always deal with without hacking converters because Jackson 1 and 2 have completely different namespaces (because of the migration back from codehaus to the fasterxml domain).

That changes now with Spring Integration 3.

My personal check list when migrating:

  1. Ensure no Jackson 1.x is in the classpath anymore. Yes, check it again. There are sometimes these little annoying transitive dependencies. If so, the automatic/magic resolver (aka legacy compatibility code) of Spring Integration will prefer it. You can handle this with custom transformers, but not the built-in directives.
  2. Forget the new introduced MessageConverter in case of (AMQP) gateways, because it will not be used in the situation of message replies (INT-3285 which was actually a regression bug and will be fixed in 3.0.2).
  3. Know the existence of a Jackson’s ObjectMapper wrapper. Yes, really. The JsonObjectMapper can contain both Jackson1 and Jackson2 ObjectMappers.
  4. After point 3: If you want to customize the ObjectMapper (i.e. for a simple mapper.registerModule(new JodaModule());) you have to provide such a JsonObjectMapper. Easy with a small config.
  5. After point 4: Do not forget to add this custom ObjectMapper for each JSON transformer in use.

An example:

<beans>
<!--
 Both json-to-object and object-tojson transformer needs the constructor
 argument "object-mapper" which uses the custom mapper defined in IntegrationConfig
-->
  <int:chain input-channel="requestChannelJson" output-channel="requestChannel">
    <int:json-to-object-transformer object-mapper="jsonObjectMapper" type="your.package.to.response.Type"/>
  </int:chain>
  <int:chain input-channel="replyChannel" output-channel="replyChannelJson">
    <int:object-to-json-transformer object-mapper="jsonObjectMapper"/>
  </int:chain>
</beans>

Updated 15.02.2014 adding reference to INT-3285

Updated 03.05.2014 INT-3285 resolved with release of Spring Integration 3.0.2

Can you trust your npm dependencies?

Maybe.

OS X 10.9 Mavericks: SourceTree funktioniert nicht mehr, kein Git-Svn mehr?

Auch nach einer manuellen Neuinstallation der MacPorts funktioniert Git-Svn und damit auch Tools wie SourceTree nicht mehr, weil Libraries (hier zu Perl) nicht mehr gefunden werden.

Temporäre Abhilfe verschaffen hier  zwei Symlinks.

sudo ln -s /Applications/Xcode.app/Contents/Developer/Library/Perl/5.16/darwin-thread-multi-2level/SVN /System/Library/Perl/Extras/5.16/SVN
sudo ln -s /Applications/Xcode.app/Contents/Developer/Library/Perl/5.16/darwin-thread-multi-2level/auto/SVN/ /System/Library/Perl/Extras/5.16/auto/SVN

OS X 10.9 Mavericks: Kostenloses iWorks Update für DVD-Kunden

Aktuell wird für Kunden, die die iWorks Suite noch von einem DVD-Datenträger installiert haben (und eben nicht via Mac App Store), kein kostenloses Update für Keynote, Pages und Numbers angeboten — zumindest in Deutschland.

Stellt man seine Systemsprache auf Englisch und bootet neu (vielleicht reicht auch aus- und einloggen), dann werden die kostenlosen Updates angeboten.

Danke für den Tipp!

Ach ja, übrigens: Weil das Upgrade durchaus Features weniger hat, empfiehlt sich unter Umständen ein Backup der alten Software. Prinzipiell sind die ja auch beide parallel lauffähig.