04.04.2015 - Java Programming Question, Unique but sorted

When doing technical job interviews I often ask my candidates simple questions to see how good their knowledge of several aspects of the Java programming language is.

The most basic knowledge every programmer must have is: data structures and algorithms. Therefore the most basic knowledge every Java programmer must have is: the Collections framework. The following examines the candidates knowledge on sets and lists (and their differences). The key isn’t to solve the question, but to show you why you did what you did.

The question

You are given a list of 1000 strings. Write a program that will remove any duplicates from the list while keeping the order.

The naive approach

The naive approach is to walk over the given list and add all elements to a result list, that does not yet contain the current element. The following example code demonstrates this:

public List<String> filter(List<String> strings) {
  List<String> result = new ArrayList<>();
  for (String string : strings) {
    if (!result.contains(string)) {
      result.add(string);
    }
  }
  return result;
}

This will produce the correct result. Let’s examine this code for two factors: Memory usage and runtime (measured in Big-O complexity).

Memory usage is quite low in this example. We use the 1000 strings which are already in memory and create a new list with references to them. No worries here.

Let’s examine the runtime next. The part of this example algorithm are:

  1. Walking the input list of strings
    This is unavoidable. We must take a look at each of the elements in the input list, which mean O(n)
  2. Checking if the result list already contains the current string
    The cost of this call depends on the implemenation within the class ArrayList. This is something an educated Java developer must know (or at least must guess correctly). In a best case scenario the element we are looking for is the first one. The worst case is that the element is the last one. Therefore the implementation of ArrayList must walk the result list from the beginning to the end for each contains() call, again O(n).
  3. Inserting the element in the result list
    Inserting an element to the end of an ArrayList is cheap (i.e. O(1)), but (an this is again something to identify an educated developer) only if there is enough room left in the array. If there is not enough room left (the data array within the ArrayList is full), the ArrayList will have to grow(). This will result in a call to Arrays#copyOf(), which will create a new array in memory and copy over the elements, which again means O(n). Note that this will happen more seldom, because ArrayList does a good job ensuring grow() doesn’t get called to often.

This results in a complexity of O(n²), because with the loop over the given strings we loop over the result set. If you come up with this solution, you definitely must give the explanations above. And you definitely must show the interest to improve your answer!

The educated guess

Now we know the naive approach is expensive because of it’s contains() calls. The next step is to think about what we can do to improve this. Another data structure provides a faster implementation of contains(): the Set. But simply jumping on this data structure is not enough, because one thing is not featured by this data structure: keeping the order elements were inserted. Using these two data structures we can implement the requested functionality.

public List<String> filter(List<String> strings) {
  List<String> result = new ArrayList<>();
  Set<String> seen = new HashSet<>();
  for (String string : strings) {
    if (!seen.contains(string)) {
      result.add(string);
      seen.add(string);
    }
  }
  return result;
}

Again, let’s take a look at the memory usage and complexity. The memory usage is low again, and only slightly more expensive. The implementation of HashSet uses a HashMap internally, which means it will store the references to the strings in memory plus the hashcode for them (i.e. 1000 integers).

Determining the complexity of this algorithm gets a bit harder.

  1. Walking the input list of strings
    Same as above, no changes here
  2. Checking is the element is already present in the result
    As mentioned the implementation of Set#contains() is cheaper than List#contains(). This is due to the fact that it will use Object#hashCode() to check if the element is already present. The HashMap used in the HashSet will guarantee that this is O(1). Note: if you also mention that on a worst case a HashMap could have O(n) due to using a single hash bucket, you would definitely gain extra points!
  3. Adding the element to the result list
    Same as above, no changes here
  4. Adding the element to the set
    HashMap#put(), which is used by HashSet#add(), also has O(1). Note that we could also trigger a HashMap#resize() here.

Now our algorithm has linear complexity O(n), which is way better than the quadratic complexity before.

Getting immediately hired

If you are a long time Java developer, you are likely to come up with the solution above. You would now be presented with the question: “Can we do better than this?”

The answer is that O(n) is the best we can do in regards of complexity. We must take a look at each element of the list at least once. Therefore we can’t get below O(n).

But in regards of the implementation there are several points we can still improve. First of all we could initialize our result List and seen Set with appropriate capacities to reduce calls to ArrayList#grow() or HashMap#resize(). If nothing else is specified in JDK 8 an ArrayList is initialized with space for 10 elements, and an HashMap with 16 elements for a load of 0.75. This is way too small for 1000 elements.

If you point out LinkedHashSet in the interview, chances are good that you could be hired immediately. This simplifies the implementation to the following two lines:

public List<String> filter(List<String> strings) {
  Set<String> result = new LinkedHashSet<>(strings);
  return new ArrayList<>(result);
}

This implementation avoids all manual size initialization and iteration mentioned above.

15.03.2015 - Bootstrap Navigationstabs mit AngularJS als aktiv markieren

Wenn man eine neue Technologie wie AngularJS ausprobiert, sollte man mit einer möglichst einfachen Aufgabe beginnen. Yeoman erstellt bereits das notwendige Codegerüst für uns, aber es erstellt ein bootstrap-basiertes Menü, dass das Home-Element immer als aktiv markiert (zumindest in der aktuell verfügbaren Version 0.11.1). Dieses kleine Tutorial erklärt wie man den Code anpasst, um diese einfache Funktion zu implementieren.

Beginnen wir mit yeoman

Für dieses Tutorial ist es notwendig, dass du bereits Node.js und npm kennst und installiert hast. Wir starten also mit der Installation von yeoman:

mkdir bootstrap-navigation-example
cd bootstrap-navigation-example
npm install generator-angular

Der nächste Schritt ist das entsprechende Codegerüst für eine AngularJS-basierte App zu erstellen

yo angular
? Would you like to use Sass (with Compass)? Yes
? Would you like to include Bootstrap? Yes
? Would you like to use the Sass version of Bootstrap? Yes
? Which modules would you like to include? (Press  to select)
❯◉ angular-animate.js
 ◯ angular-aria.js
 ◉ angular-cookies.js
 ◉ angular-resource.js
 ◯ angular-messages.js
 ◉ angular-route.js
 ◉ angular-sanitize.js
 ◉ angular-touch.js

Anschließend kannst du dir die neu erstelle App mit folgendem Befehl ansehen:

grunt serve

Beim anklicken von “About” wirst du die About-Seite unter /#/about sehen (das passiert dank angular-route), aber das CSS wird weiterhin den “Home”-Tab als aktiv markieren.

About menu tab not active

Das Menü reparieren

Zuerst müssen wir die problematische Stelle im Code finden. Wir öffnen also die Datei app/index.html und sehen uns die bootstrap Navigationsleiste an:

<div id="js-navbar-collapse" class="collapse navbar-collapse">
 <ul class="nav navbar-nav">
  <li class="active"><a href="#/">Home </a></li>
  <li><a>About </a></li>
  <li><a>Contact </a></li>
 </ul>
</div>

Wie leicht zu sehen ist, ist für das li-Element “Home” der CSS-Stil “active” fest eingetragen. Wir wollen diese Logik jetzt durch einigen AngularJS-basierten JavaScript-Code ersetzen. Da wir eine CSS-Klasse setzen wollen, werden wir das Attribut “ng-class” verwenden.

<div id="js-navbar-collapse" class="collapse navbar-collapse">
 <ul class="nav navbar-nav">
  <li><a href="#/">Home</a></li>
  <li><a>About</a></li>
  <li><a>Contact</a></li>
 </ul>
</div>

Wir haben jetzt also folgendes geändert: Zum Einen haben wir einen ng-controller mit dem Namen “HeaderCtrl” zum Menü hinzugefügt, zum Anderen haben wir eine ng-class zu den Menüelementen angegeben. (Hinweis: Wir lassen in diesem Tutorial “Contact” absichtlich außen vor, da yeoman weder eine angular-route, noch einen Controller noch eine View für die “Contact”-Seite erstellt). Anschließen wollen wir natürlich den passenden Controller erstellen, um den Ausdruck in ng-class auswerten zu können. Wir fügen diesen neuen Controller in app/scripts/app.js ein (Es gibt einige Tutorials, die den Controller in der controller.js hinzufügen. Die ist aber nicht der Fall für eine App erstellt mit yeoman). Wir fügen also folgenden Code in das AngularJS-Modul am Ende der Datei ein:

  .controller('HeaderCtrl', function ($scope, $location) { 
    $scope.isActive = function (viewLocation) { 
      return viewLocation === $location.path();
    };
  });

Wenn du jetzt zurück in den Browser wechselst (und “grunt serve” bereits die Änderung erkannt hat), wirst du sehen, dass das About-Tab als aktiv markiert ist.

About menu tab is active

Ergebnis

Jetzt hast du gesehen, wie einfach es ist, mit AngularJS die ersten Schritte zu gehen und wie leicht du neue Funktionen in deine Applikation einbauen kannst. Nutze dieses Wissen und erstelle deine eigene Webapplikation.

14.03.2015 - Continuous Integration Setup

Improving the code quality of software in an everyday process is challenging. It consists of multiple parts like unit and integration tests, test code coverage, static code analysis including code metrics and proper comments. All this work is additional to main task of software developers: creating fantastic new features … and fixing bugs from time to time. Over the years I’ve played around with several tools to easy this task for all parties involved and come up with a solution, that performs most of the job automatically. Without no further ado I present you a continuous integration setup that I think works best (it’s actually very similar to what my company is doing).

Overview of the continuous integration setup

continuous_integration_setup

Now that you managed to scroll over the large image you want to know more of the details, right? First of all this scenario is meant for Java EE based development processes, but I see no reason not to apply it to other types of developments, too (but keeping in mind that some components might need different implementations). I’d like to look at this from two different angles: the developer view and the manager view.

Developer view

When doing development I want my focus to be on the primary target: adding a new, cool feature. In the currently workflow at my company it is necessary that I also add a black-box test case for whichever code I added to verify I did well. The next step (usually done by a fellow software engineer of the same team) is to convert the black-box test case into a white-box test case, by expanding to cover most of the code paths (especially including negative testing). We are currently focussing on integration tests (i.e. not testing using mock objects, but on a dedicated machine hosting the complete software including a database), simply because we want to test a scenario most similar to our production system. Also having a large integration test suite is really awesome, as it can be easily used for regression testing.

But integration tests are not suited for running the tests on a developer machine. The main reason is that the tests are quite time consuming and required lots of resources (RAM, CPU, etc.). Another reason is that comparing the results is like comparing apples and pears: They were done on different systems with possibly different configurations and possibly different datasets. This is where our automated process comes into play: Each time a developer commits his code and pushes it to the central server (we are using Git), our build server will go ahead and compile our software, run the unit tests and notify the developer of bad results. Now we have a built- and unit-tested piece of software. The next step is: Running the integration tests and, also, getting notified about bad results. In best case scenarios the developer will not be notified about anything, which makes every developer happy.

After a successful result the last step is publishing the artifacts. There are two possible points on when to publish the built artifact: Either after it was built- and unit-tested or after it was verified by the integration tests. It boils down to the question: Is an artifact with a failed integration test still a valid artifact? In my current process we accept artifacts with failed integration tests for non-release versions (i.e. maven SNAPSHOT versions), but not for software to possibly be deployed to production servers.

And this is basically where the developer view ends. Every developer is encouraged to look at other measurements for quality, but in a team solely consisting of senior developers it’s not essential.

Manager and quality assurance view

All information must be aggregated in some kind of portal to be easily accessible for everyone. From a management perspective it can be used to see how good (or bad) things are going. This is essential for everyone not directly involved in the actual development process, but still working on or working with the product in development. So the portal is primary used by software architects, team leads, even CTOs or vice presidents (and of course the product owner in a scrum process).

When diving deeper into the metrics, test results and documentation the same portal can be used for quality assurance. It helps the product owner to verify if stories were implemented properly (e.g. no failing tests and proper documentation) or testers to identify which parts of the software aren’t completely tested yet and write tests for those cases. The real crucial part is to aggregate the information in a proper way. In our setup SonarQube does a lot of this work for us; it provides coverage for unit and integration tests next to code metrics. Other tools can be used as well (e.g. Checkstype, FindBugs, or PMD) and there are really good plugins integrating the data into Jenkins.

A key component is also automatic delivery of the software to an internal test system. It is a reference system hosting the latest software for everyone; holding the necessary configuration options, specifying the matching database and also providing a stable test system for the latest code.

Final words

Obviously: Setting up the complete infrastructure is a little bit time consuming, but it is absolutely worth it. Many components have to be brought together, but the grade of automation really simplifies the everyday work. The key is to have a transparent development process especially highlighting its weaknesses. This enables developers to improve their skill and largely improves the code quality.

A final remark is that not all default rules of several analysis tools will match your project. You have to keep in mind that tweaking the rules (e.g. starting with a little bit more relaxed rules) is an essential part of setting up your infrastructure. It will allow you to start with a decreased amount of issues.

06.06.2014 - Creating an "Indiana Jones flight map effect" animation

I recently saw a simple 2D animation that rendered in a red line how a plane moved over a map. This is what you might also know as the “Indiana Jones flight map effect”. I immediately had an idea on how to do this in Blender so I went ahead and did it. Here is the result:

animation
(large).

How to achieve the effect

The idea is quite simple: To make the red path appear on the map we move it from behind the map to front of it. The trick is that the path isn’t planar to the map but the front is “higher” than the end of the line. This way moving it through the map will make the red line appear at the start first and reveal more and more until the line reaches the end.

So first of all you need to create the background map for your animation. I used tiles from OpenStreetMap on 3×3 planes for this, but you can use whatever background you prefer. Afterwards you need to create the line the flight will take. I thought using a straight line is boring, so I went for a curve. I created a bezier curve to move along the way you want to animate. Make sure you create a 3D curve, because we need the Z-axis for our animation. Also make sure to set the curves “Twisting” to “Z-Up” which is necessary that the line is flat in relation to the map. Once you are satisfied with your path, you need to add a mesh to solidify the curve. Use a simple small plane for this, set its color to red and add two modifiers:

  • Array: This will convert the plane into a line. Adjust width and height until you are satisfied with your line.
  • Curve: This will make your line follow the curve.

The red material must not cast any shadows. If you are using cycles to render the animation I recommend creating the material as shown in Blenderartists thread Cycles: make object cast no shadow.

After you modeled your path (the mesh and the curve) move it behind you map. Afterwards insert a location keyframe (press “I” and select “Location”) for both, go to your target frame (e.g. 90), move the line to the front and insert another location keyframe. Blender will now interpolate between the two points for you. Press “Alt+A” to see a preview of the animation. You might need to adjust the curve to make the animation look smooth (rotate some nodes, add some notes, etc.). Once satisfied go ahead and render the animation.

To create a GIF from the generated PNGs you can (as for most imaging automation tasks) use imagemagick:

convert $( for a in 00*.png; do printf -- "-delay 10 %s " $a; done; ) result.gif

Feel free to play with the final blend file.

24.03.2014 - Scrum from a management point of view

I recently had a discussion with a friend of mine regarding the usefulness of Scrum. I’ve taken some helpful hints from the discussion on how a developer can feel used and misused by Scrum. Let’s talk about a few of them, but let’s start with some naked rules of Scrum first:

  1. The daily work of a developer is bound to the user stories of a sprint.
  2. Due to the nature of time only a limited amount of this resource can be spent during a sprint.
  3. The customer is expecting a result according to his wishes in the shortest time possible.

Theory: Scrum stops creativity

I can agree with this only partially. The truth is: The customer is setting the requirements and, most important, he pays for reaching them. That means: he is setting the direction where the project is heading, no matter how strange some requirements might appear to the developer. But of course that does not mean everyone should blindly follow a wrong direction. So what happens if a developer has a really good idea on how to improve the product? It’s really simple: Take the input from your developers and take it to the customer. If the idea is really that good, he will agree on implementing it. From my point of view the creativity is not harmed by Scrum in any way. Everyone can still suggest ideas, but you should not go ahead an implement them without permission of the customer. Next to that: It’s hard to plan when a developer might have that one brilliant idea.

Theory: There is no time to do things right

I can not agree with this at all. First of all it is really to find a proper definition of right. What is the right way to implement a search functionality? Performing a LIKE-search on a database column? Or use weighted search on a lucene index using a solr cluster? Both attempts have obvious advantages and disadvantages. A search using an index is likely to be more natural to the end user, but it might not even make a difference. And searching a small table with a couple of lines can perform really well, but what about millions of lines?

To me this boils down to one question: How good are my user stories? When a story is well defined (specifying the use cases, the amount of data and the likelihood of usage) it is easy to find the right solution. If it’s not a developer might go for a technically interesting but expensive solution. If a story is well defined, the estimated development time will be large enough give the developer enough room to implement a solution properly. If it’s not be prepared for bad code.

Theory: Implementations must be shortsighted

I partially agree with this. One of Scrums basic ideas is: “only implement what you really need”. In most cases a developer will have to focus on a single feature/problem without having the complete spectrum of future requirements in mind. In most cases this results in solutions very specific to the given problem.

Theory: No time to undo mistakes of the past

I largely agree with this. When a developer is working on a new feature it commonly happens that he will go through a lot of existing code. And every code base has established concepts of doing things and these are accepted by the developers. But from time to time some concepts have proven to be bad and need to be reworked. But the customer will not be very happy when, after months and years of work, being presented a product that looks exactly the same as before. It’s almost impossible to find a customer paying for this! So if your developers are completely used by the Scrum there is no time to fix the so called technical debt. In my experience it is good to stop the Scrum process from time to time to allow the developers to perform larger cleanups. Alternatively it also works to have a sprint without enough user stories to consume the whole time available.

Conculsion

I agree that a developer might feel controlled by the customer/product owner/scrum master and being less able to establish his own ideas. But in my experience that often boils down to improper usage of Scrum. Having good user stories and a bidirectional communication with all involved parties not only leads to better products, but most important to happier developers. When everyone involved in the Scrum process is fulfilling the required role, it can be an enjoyable development experience for all sides.

10.02.2014 - Finding relevant images in a large set of files

I recently had to recover data (images to be precise) from a 1 TB large drive. I used photorec to find the data on the drive. It resulted in lots and lots of images within lots and lots files. How do you find the relevant images within that amount of data? For initial filtering I focused on a single criteria: image dimension. I wrote a little script to find all images, check their size, and symlink them to a folder sorting them by YEAR/MONTH/DAY. You can invoke them by calling

./findimages.sh /some/directory

. It will produce /some/directory/found with accoring subfolder for the date of the image. Note that you need the exiv2 binary to properly use this script.

#!/bin/sh

export LC_ALL=C
DIR='${1}'
TARGET_DIR='${DIR}/found/'

function symlink() {
	IMAGE="${1}"
	EXIV="${2}"
	IMAGE_DATE=$(echo "${EXIV}" | grep "Image timestamp" | sed -e "s/Image timestamp\s*:\s*//")
	DATE_FOLDER=$(echo ${IMAGE_DATE} | sed -e "s:\([0-9:]\+\) [0-9:]\+:\1:" | sed -e "s|:|/|g")
	mkdir -p "${TARGET_DIR}${DATE_FOLDER}"
	ln "${IMAGE}" "${TARGET_DIR}${DATE_FOLDER}"
	sync
}

COUNT=$(find ${DIR} -name '*.jpg' 2> /dev/null | wc -l)
CURRENT=1

for IMAGE in $(find ${DIR} -name '*.jpg' 2> /dev/null); do
	echo "${CURRENT}/${COUNT}"
	CURRENT=$((${CURRENT} + 1))
	EXIV="$(exiv2 ${IMAGE} 2> /dev/null)"
	IMAGE_SIZE=$(echo "${EXIV}" | grep "Image size" | sed -e "s/Image size\s*:\s*//")
	if [[ ${IMAGE_SIZE} =~ ^[0-9]+( )x( )[0-9]+.*$ ]]; then
		X=$(echo ${IMAGE_SIZE} | sed -e "s:\([0-9]\+\) x [0-9]\+:\1:")
		Y=$(echo ${IMAGE_SIZE} | sed -e "s:[0-9]\+ x \([0-9]\+\):\1:")
		if [ "$((${X} * ${Y}))" -gt "786432" ]; then
			symlink "${IMAGE}" "${EXIV}"
		fi
	else
		echo "${IMAGE}: ${IMAGE_SIZE} (${EXIV})"
		symlink "${IMAGE}" "${EXIV}"
	fi
done

If you have suggestions on how to improve the script or smarter alternatives, please let me know

27.11.2013 - nginx + cgit in a subfolder

I’ve recently decided to give nginx a try. So far I’ve used Apache httpd 2.4 exclusively, but I wanted to get to know the competitor prior to sticking with Apache httpd or switching to nginx depending on the result. There are lots of claims about nginx’s performance and Apache httpd’s bloat, but I simply wanted to get started with a test scenario. For me this scenario was running the cgit web interface on http://localhost/cgit/. Next to the configuration files the only major difference to me is: nginx only provides a FastCGI interface, while I was using the built-in CGI interface in Apache. Luckily FastCGI is not hard to set up nowadays. On ArchLinux it basically boils down to the following three commands:

pacman -S nginx fcgiwrap
systemctl enable fcgiwrap.socket
systemctl start fcgiwrap.socket

After this you can use FastCGI, and thanks to systemd it is socket activated, i.e. it is only started when someone is accessing it. Afterwards I reused my /etc/cgitrc from the previous Apache httpd, which looks more or less like this:

root-title=My git Server
root-desc=This is my very own git server!
css=/cgit-web/cgit.css
logo=/cgit-web/cgit.png

virtual-root=/cgit

section=Some section

repo.url=Some Repo
repo.path=/srv/git/somerepo.git

For me the largest obstacle was setting “virtual-root = /cgit”, which was not necessary for Apache httpd, but mandatory for nginx. This has to match the property set in /etc/nginx/nginx.conf

http {
 ...
 server {
 ...
   location /cgit {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi;
    fastcgi_pass unix:/run/fcgiwrap.sock;
    fastcgi_split_path_info           ^(/cgit/?)(.+)$;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param QUERY_STRING $args;
   }
   location /cgit-web {
    rewrite ^/cgit-web(/.*)$ $1 break;
    root /usr/share/webapps/cgit;
   }
 }
}

After performing this small amount of configuration in nginx the server was up and running. In my very own and non-representative test scenario nginx and Apache httpd performed very similar (tested using jmeter). Even the memory usage was not that different. So at least for me the difference was not enough to convince me to permanently change my setup for now. Most of the things I need (PHP, ~/public_html, cgit) work fine on both, and my Apache httpd configuration is solid and proven for years.

If you have other suggestions on why to use nginx over Apache httpd feel free to inform me about it.

12.10.2013 - Unit testing with junit and mockito

If it’s not tested, it’s broken. – Bruce Eckel

I’m a great fan of reliable software. And as a software developer I only want to create software that works reliable. In my opinion crashes in any software (or even worse: data loss) cause distrust from the user. Would you want to run a piece of software that crashes? I wouldn’t. That’s why I think that testing software (and finding crashes before your user does) is a very important part of software development.

So how do we test software? As usual Wikipedia knows lot’s of testing types. You see, there is a large amount of ways to test software. I’ll focus on testing typically done by software developers: unit testing. Unit testing is done, as the name suggests, one a “unit” of the software. I prefer to use my classes and their methods as my units, others might do differently. So let’s start with a trivial example unit, the SomeDao:

package de.egore911.test;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Id;

public class SomeDao {
	public static class Some {
		@Id public Integer id;
	}

	@Inject private EntityManager em;

	protected EntityManager getEntityManager() { return em; }

	public Some comeGetSome(Integer id) {
		return getEntityManager().find(Some.class, id);
	}
}

This code is really simple. We have a DAO (data access object) which is able to load entities of the type Some by their ID. The class itself uses CDI to inject the EntityManager instance. This is a very common type of class I’ve seen in lots of web projects, but how to test this unit? At first glance it depends on an injection framework, which needs an entity-manager, which needs a database, which needs dummy data. This is a lot and lot’s of things could cause the test to fail that should not be part of this unit test (e.g. the database was not available). So we need to have a mock object for the EntityManager, which does not actually need to be injected and also does not need a database. This is where mockito comes into play.

import javax.persistence.EntityManager;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

public class SomeDaoTest {

	@Test
	public void testComeGetSome() {
		// Mock the EntityManager to return our dummy element
		Some dummy = new Some();
		EntityManager em = Mockito.mock(EntityManager.class);
		Mockito.when(em.find(Some.class, 1234)).thenReturn(dummy);

		// Mock the SomeDao to use our EntityManager
		SomeDao someDao = Mockito.mock(SomeDao.class);
		Mockito.when(someDao.comeGetSome(1234)).thenCallRealMethod();
		Mockito.when(someDao.getEntityManager()).thenReturn(em);

		// Perform the actual test
		Assert.assertSame(dummy, someDao.comeGetSome(1234));
		Assert.assertNull(someDao.comeGetSome(4321));
	}
}

You can see that this is fairly simple. First you mock an EntityManager that will return a dummy object when the EntityManager.find() method called. Then we make sure our mocked EntityManager is returned when SomeDao.getEntityManager() is called and also the real SomeDao.comeGetSome() is invoked. Of course all this could be done using reflection ourselves, but mockito does all this groundwork for us.

Mockito offers some other nice features, but my primary use is stubbing method calls.

10.07.2013 - Creating a chair in Blender

Heute war mir danach … in Blender einen Stuhl zu modellieren! Hier sieht man das virtuelle Ergebnis. Wenn ich jetzt nur noch wüsste, wie man aus Holz einen Stuhl baut ;-)

A concept chair

Das Modell wurde vollständig in Blender erstellt und mit Cycles gerendert.

27.06.2013 - Securely storing passwords in databases

Whenever I hear about users credential data being stolen from servers I wonder how good (or bad) it was stored in regards of security. There are several layers of security I apply to passwords. The following article will explain these layers and my reasons for them. I’ll explain these starting with the worst example I’ve ever seen in production.

Starting of really bad

I was assinged to work on a web application once, that contained the following table:

login password email
user1 123456 user1@hotmail.com
user2 somedude22 randomguy@somemail.com

This was a table storing the plain text password along with the username and the email address. This is the absolute worst case scenario, because users tend to reuse the same username, email and password combinations. It is even likely that the password for the e-mail address would be the same as stored in the database. If an attacker would get access to this database it would not only harm the application the password was stolen from, but possibly the whole digital identity. If the same credentials were used for an online store it is possible the attacker could get access to credit card numbers and similar sensitive information.

Another very critical point is that the password may contain personal information (like religious view or sexual orientation) you are not allowed to store without explicit permission of the user. I’m not aware of any lawsuite regarding this topic, but I wouldn’t want to be the first.

Hashing passwords

To improve this it is actually a wise decision never to store the users password, only a hashcode of this password. I rely on hashing algorithms natively supported the technology stack used when developing an application. In the past I commonly used MD5, but nowadays I tend to use SHA-1. Feel free to pick whatever hashing algorithm suits your needs or that you are familiar with. The only restriction is that you should never use an algorithm known to be weak or even one that was already broken.

Important note: Some might argue SHA-1 is already broken. This is formally correct, but right now there is no implementation for the strategy proposed in breaking it. Next to that it’s an algorithm supported by many layers of the technology stack (e.g. MariaDB and Java). I would no longer use it if I would be starting a new application, but rather SHA-256.

login password email
user1 f447b20a7fcbf53a5d5be013ea0b15af user1@hotmail.com

Now you only have stored the password with a little bit of security applied.

Protecting users with weak passwords

It is hard to determine the plain text password from the stored hashes, and it is really expensive. You can use brute force to calculate the hashcode for lots and lots of passwords until you find a match. But the greatest threat to breaking the passwords are rainbow tables. A rainbow table basically is a really large table storing the hashcode along with its input. The table is then used to lookup hashcodes to quickly get the input. Common passwords, like ‘123456’, will be broken within a fraktion of seconds. To protect users with weak passwords you need to use ‘salting’. This basically means you append a constant random string to the password prior to calculating the hashcode. If the users passwords was 123456 and our salt would be atho3aifeiR2, the string sent to the hashcode calculation would be atho3aifeiR2123456. If you choose your random string wisely it’s unlikely rainbow tables will contain this. Next to that most of the rainbow tables were built using only short passwords. If the salt itself is lengthy (e.g. 12 chars and more) it provides and additional chance of it not being in the rainbow table. So never use short and easy salts, like ‘1’ because this does not provide any security at all.

Double hashing passwords

Now your passwords are stored pretty secure. But if the attacker was able to obtain your salt with the hashed passwords he could still build a rainbow table for all passwords starting with your salt. For simple passwords this would still harm the security. I’m using a chain of hashing algorithms to work around this. Basically you salt the password and hash it as done before, but after that you go ahead and calculate the hashcode of the hashcode. You can repeat this step several times, like

md5(md5(md5('atho3aifeiR2' + password)))

. This way a possible attacker can not use any rainbow table but only rely on brute force attacks. The great advantage of this approach is that the attacker needs to know your implementation to actually produce usable results. If he was able to break into your database server but not your application server, your users passwords are safe.

Protecting against weak algorithms

If you used a weak algorithm (or one that was broken after you introduced it) your users still could be at risk. If you use a chain of different algorithms this threat is actually minimized. So our pseudo-code looks like this

SHA2(sha1(md5('atho3aifeiR2' + password)), 256)

. In case all of these were broken, you can still wrap the whole chain using a stronger algorithm, like

SHA2(SHA2(sha1(md5('atho3aifeiR2' + password)), 256), 512)

, and apply the outer most hashfunction to your existing data, e.g.

UPDATE user SET password = SHA2(password, 512)

13.02.2013 - Testing different libGL implementations

I recently learned that the Intel i965 hardware is capable of handling GLSL 1.30, but nobody got around to add support for this in the DRI/mesa 3D driver. The developers at Intel are focusing on their latest hardware which means GLSL 1.30 support won’t be added soon. The core mesa supports GLSL 1.30 and later generations of the Intel hardware are supported as well. Luckily Intel provides all the necessary 3D documentation that allows anyone to implement it.

But how do we get started? First of all you need to test the driver and see where you are starting. The best way to do this is using piglit. Piglit is an awesome tool maintained by the open source mesa developers to perform reproducible tests. You can see it as a conformance suite or a regression test. So the first thing is figure out what tests from piglit can be used to check for GLSL 1.30 support. Piglit ships lots of tests for specification conformance, including tests/spec/glsl-1.30.

Piglit also ships some test profiles, including all.tests. This will execute all tests known to piglit. For our purpose it is sufficient only to run the GLSL 1.30 tests. I went ahead and commented the tests not relevant for now.

$ ./piglit-run.py tests/all.tests results/2013-02-13_base
$ export MESA_GLSL_VERSION_OVERRIDE="130"
$ ./piglit-run.py tests/all.tests results/2013-02-13_base_130
$ ./piglit-summary-html.py --overwrite out results/2013-02-13_base*

I started with the command listed above. It will run the piglit tests using your currently installed driver. The first run will be using GLSL 1.20 which is announced by the driver, the second run will use 1.30. After that you can generate a nice HTML form to show the differences. If everything went fine you will quickly see tests changing from skipped to failed or passed. These will be the tests you will need to look into.

For me the tests caused a GPU lockup somewhere in the tests. This is to be expected when overriding the GLSL version to something not supported by the driver. Only use this when you are developing the graphics driver! Piglit already wrote parts of the result file so I started to compare the incomplete differences and picked the first that failed. In my case this is varying-packing-simple float separate -auto -fbo which caused a segfault (it’s not the GPU lockup, but let’s start with an easy example). Before you start of installing debug packages for you distribution you should verify that a failure is still present in the latest git code. It is best to build mesa using the same configuration options as your distribution does (I’m not going into the details of how to get these as they vary from distribution to distribution).

Now on to the interesting part: How do you use a different version of libGL and the DRI drivers without messing with your installed drivers? It’s pretty easy once you know the trick. First of all you need to tell the linker where to look for shared objects.

$ ldd varying-packing-simple float separate
  ...
  libGL.so.1 => /usr/lib/libGL.so.1 (....)
  ...
$ export LD_LIBRARY_PATH=/home/cbrill/source/mesa/lib
$ ldd varying-packing-simple float separate
  ...
  libGL.so.1 => /home/cbrill/source/mesa/lib/libGL.so.1 (....)
  ...

Now you managed to load a different libGL.so when you are executing you tests. But be aware: libGL will dynamically load your installed hardware drivers! This might cause some crashes if the installed driver does not match the development libGL.

$ export LIBGL_DRIVERS_PATH=/home/cbrill/source/mesa/lib
$ export EGL_DRIVERS_PATH=/home/cbrill/source/mesa/lib/egl

Now you are using your a local copy of mesa to test your implementation. The benefit of user space 3D drivers is pretty huge here, because otherwise you’d have to load/unload a kernel module very often. And debugging crashes in kernel space is much more complicated than in user space.

In my case the segfaulting test no longer crashed when using mesa from git. I’m currently in the process of generating a piglit run but I get a GPU lockup and don’t see the results. A good recommendation would be to run tests from a different machine that is not affected by your test (e.g. serial console or ssh connection). To run applications on the display when connected by ssh you need to do the following on you test machine

$ xhost +

After that that you can run any command, e.g. glxgears, on that display by doing:

$ DISPLAY=:0 glxgear

That pretty much sums up everything you need to test your driver. Have fun!

06.12.2012 - How to create a Android file browser in 15 minutes

Android provides very useful components to create Apps very fast. That sounds like a marketing claim, does it? OK, let’s see if that acutally is true! Let’s create an Android file browser.

Let’s start off by create a default “Hello World”-App that will consist of a layout file and a matching activity. Knowning what we want to build we name the layout activity_list_files.xml and name the Activity ListFileActivity. If you are developing using eclipse the default layout editor will show up displaying your wonderful “Hello World”-App. Let’s start by replacing the layout using the following code:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent" android:layout_height="match_parent">
  <ListView android:id="@android:id/list" android:layout_width="match_parent"
    android:layout_height="wrap_content" />
</LinearLayout>

Now you have a very simple layout which only consists of a single element, a ListView. The ListView will be the component displaying our files. That’s it? Yes it is! But how will it be populated with data? That’s where our activity comes into play.

public class ListFileActivity extends ListActivity {

  private String path;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_list_files);

    // Use the current directory as title
    path = "/";
    if (getIntent().hasExtra("path")) {
      path = getIntent().getStringExtra("path");
    }
    setTitle(path);

    // Read all files sorted into the values-array
    List values = new ArrayList();
    File dir = new File(path);
    if (!dir.canRead()) {
      setTitle(getTitle() + " (inaccessible)");
    }
    String[] list = dir.list();
    if (list != null) {
      for (String file : list) {
        if (!file.startsWith(".")) {
          values.add(file);
        }
      }
    }
    Collections.sort(values);

    // Put the data into the list
    ArrayAdapter adapter = new ArrayAdapter(this,
        android.R.layout.simple_list_item_2, android.R.id.text1, values);
    setListAdapter(adapter);
  }

  @Override
  protected void onListItemClick(ListView l, View v, int position, long id) {
    String filename = (String) getListAdapter().getItem(position);
    if (path.endsWith(File.separator)) {
      filename = path + filename;
    } else {
      filename = path + File.separator + filename;
    }
    if (new File(filename).isDirectory()) {
      Intent intent = new Intent(this, ListFileActivity.class);
      intent.putExtra("path", filename);
      startActivity(intent);
    } else {
      Toast.makeText(this, filename + " is not a directory", Toast.LENGTH_LONG).show();
    }
  }
}

Let’s take a closer look at the activity. First of all I’ll give a short overview of the thoughts behind this activity: The activity displays all files within a given path. If we switch the path, we switch to a new activity displaying all files within the given directory. Easy right? To achieve that we extend the ListActivity which provides us methods like getListAdapter(), setListAdapter() and onListItemClick() to interact with the list in our layout. So when our Activity is started by Android and onCreate gets called the first thing we do (after setting the layout) is: Set the path as our activitiy’s title. In the next step we are going to read all the files from the given path, but there’s a catch: Android locks several paths from being accessed by apps. This is intended and necessary to keep apps from spying on each other (the “/data”-folder for example contains all the databases from the apps, including stored credentials). For this reason we add a note to the title and we need to check if File.list() actually returns an array. The javadoc states that it will only return null if you called the method on a file, but it also is true for inaccessible directories.

The lower part of onCreate is also interesting. See how we create our data adapter? We use Android’s ArrayAdapter, which allows us to pass it a List and tell it how to render it. Really easy and actually suited for many needs. Finally the onListItemClick will launch a new instance of our ListFileActivity to display another folder. Using the back button on your device will get you back to the previous folder.

You can see that creating a very simple file browser can be done in a very short amount of time and using very few lines of code. Of course this could be improved a lot (e.g. splitting onCreate into several methods) but there are already really good file browsers available on the Google Play store (and it would take way more than 15 minutes to match their features). Anyway I hope you enjoyed this little introduction into Android development using ListView.

Thanks to Simeon M. and Laurent T. for pointing out minor typos!

28.11.2012 - Anatomie eines git Commit-Kommentars

Jeder, der mit dem Versionskontrollsystem git zu tun hat, wird früher oder später feststellen, wie ein Commit-Kommentar aussehen sollte. Für alle, die das bisher noch nicht wissen, hier mal ein kurzes Beispiel:

Kurzer Betreff, max. 80 Zeichen

Optionaler längerer Text, der den Commit beschreibt. Dieser darf gern mehrzeilg
sein und die Beweggründe erläutern.

Optionale Signaturen.

Nun stellt sich die Frage: Warum macht man das so? Dies möchte ich anhand eines praktischen Beispiels erläutern:

mesa: remove '(void) k' lines

Serves no purpose as the k parameter is used later in the code.

In diesem Commit wurden mehrere Codezeilen gelöscht. Hätte der Autor gar keinen Kommentar angegeben, wäre rätselhaft warum er dies getan hat. Glücklicherweise erzwingt git immer eine Commit-Meldung. Aber auch die erste Zeile alleine ist nicht aussagekräftig, sondern folgt dem “stating the obvious”-Prinzip. Man findet damit den Commit leicht wieder, aber man kennt immer noch nicht den Grund. Dies wird erst durch die letzte Zeile klar.

Signaturen

Es gibt in git die Möglichkeit Signaturen in einer Commit-Meldung anzugeben, z.B.:

Signed-off-by: Christoph Brill <webmaster@egore911.de>

Diese dienen dazu, zusätzliche Informationen über die an dem Commit beteiligten Personen anzugeben. Es gibt keinen offiziellen Standard für diese Signaturen, aber folgende haben sich in verschiedenen Projekten als hilfreich erwiesen:

  • Signed-off-by: Der Commit wurde durch den Signierenden in die Repository aufgenommen. Diese Meldung dient mehr oder weniger als zusätzliche Autorenangabe
  • Reviewed-by: Der Commit wurde vom Signierenden durchgesehen und für sinnvoll befunden
  • Tested-by: Der Signierende hat den Commit in seinem lokalen Sourcecode eingespielt und getestet.

Verwendung im Alltag

In einer idealen Welt würde jeder detaillierte Kommentare (sowohl im Code als auch in Commit-Meldungen) verwenden. Die Praxis zeigt jedoch, dass dies nicht immer zutrifft. Selbst disziplinierte Projekte werden Commits aufweisen, die weit von diesem Ideal abweichen. Git (wie andere Versionskontrollsysteme auch) erlaubt es allerdings mit minimal strukturierten Commit-Meldungen anderen Entwicklern (oder dem Entwickler selbst zu einem späteren Zeitpunkt) den Commit zu verstehen, ohne jede Zeile Code des Commit gelesen zu haben.

12.11.2012 - NullPointerException beim Starten von JSF 2

Die Exception

Im Zuge der Umstellung auf JSF 2.x sind mir einige Exceptions begegnet. Eine davon ist relativ trickreich zu beheben. Sie äußert sich dass beim Deployment der Anwendung auf dem Server folgende Exception auftritt:

java.lang.NullPointerException
  at com.sun.faces.config.InitFacesContext.cleanupInitMaps(InitFacesContext.java:278)
  at com.sun.faces.config.InitFacesContext.(InitFacesContext.java:102)
  at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:156)
  ...

Die Analyse

Dieser Fehler verhindert dann auch den Start der Anwendung. Woran liegt das? Dazu sehen wir uns mal eine Funktion der JSF-Referenz-Implementierung Mojarra an:

static Map getInitContextServletContextMap() {
  ConcurrentHashMap initContextServletContext = null;
  try {
    Field initContextMap = FacesContext.class.getDeclaredField("initContextServletContext");
    initContextMap.setAccessible(true);
    initContextServletContext = (ConcurrentHashMap)initContextMap.get(null);
  } catch (Exception e) {}
  return initContextServletContext;
}

Hierbei fällt auf, dass beim Zugriff mittels Reflection auf ein Feld der Fehlerfall einfach ignoriert wird und null zurück gegeben wird. Die Methode besitzt keine Dokumentation oder einen Hinweis darauf, was der Rückgabewert ist. Also muss der zugreifende Code den Fehler abfangen können. Aber tut er das? Sehen wir uns das mal an:

Map <InitFacesContext, ServletContext>initContextServletContext = InitFacesContext.getInitContextServletContextMap();
Set<Map.Entry<InitFacesContext, ServletContext>> entries = initContextServletContext.entrySet();

Damit wird schnell klar: Es wird NullPointerException geben und man sieht an der auftretenden Exception nicht den eigentlichen Grund. Dieses Fehlverhalten ist damit nicht ganz einfach zu beheben. Grundsätzlich ist es schlechter Stil eine Exception einfach zu schlucken. Besser ist es diese zumindest zu loggen, vielleicht sogar mit hilfreicher Zusatzinformation wie:

...
} catch (Exception e) {
  log.error("Could not access FacesContext#initContextServletContext, " +
    "probably JSF-API and implementation mismatch!", e);
}

Die Lösung

Jetzt ist offensichtlich, woher der Fehler kommt: die JSF-API und die Implementierung im Classpath passen nicht zusammen. In meinem Fall wurde eine weitere JSF-API über Maven als Abhängigkeit hinzugefügt, die dann “falsche” Klassen in den Classpath lädt.

Es reicht also in den meisten Fällen den Classpath der Java-Anwendung auf folgende Probleme zu prüfen:

  • Passt die JSF-Implementierung zur JSF-API?
  • Gibt es mehr als eine JSF-Implementierung im Classpath (z.B. JSF 1.x und 2.x)?
  • Gibt es mehr als eine JSF-API im Classpath?

06.07.2012 - Hibernate Reverse Engineering

Hibernate kann mit seinen Reverse Engineering Tools sehr leicht ein Modell für eine existierende Datenbank erstellen. Aber was ist, wenn diese Datenbank nicht allen Regeln der NormalForm entspricht? Fangen wir zuerst an, wie eine hibernate.reveng.xml-Datei für MS SQL aussieht:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd" >
<hibernate-reverse-engineering>
  <schema-selection match-schema="dbo" />
</hibernate-reverse-engineering>

Dieser Code legt fest, dass wir immer mit dem dbo-Schema arbeiten wollen. Dies ist bei MS SQL das Standardschema. Nehmen wir jetzt an, dass wir die Tabelle ‘XYZ’ ausschließen wollen, sprich es soll keine Mappingklasse für diese Tabelle erstellt werden:

  <table-filter match-name="XYZ" exclude="true" />

Damit taucht diese Tabelle nicht mehr auf. Jetzt wollen wir die Spalte ‘abc’ aus der Tabelle ‘ABC’ ausschließen:

  <table name="ABC" schema="dbo">
    <column name="abc" exclude="true" />
  </table>

Und die Spalte ‘def’ der Tabelle ‘ABC’ hat den falschen Typ (es stehen Zahlen in einer VARCHAR-Spalte):

    <column name="def" type="int" />

Und es fehlt auch noch ein Foreign Key von GHI auf DEF:

  <table name="GHI" schema="dbo">
    <foreign-key foreign-table="DEF" foreign-schema="dbo">
      <column-ref local-column="defId" foreign-column="ID" />
    </foreign-key>
  <table>

Und es gibt zwei Tabellen mit existierenden Foreign Keys, doch Hibernate generiert keinen brauchbaren Namen:

  <table name="GHI" schema="dbo">
    <foreign-key constraint-name="FK_GHI_GFI">
      <column-ref local-column="defId" foreign-column="ID" />
      <many-to-one property="parent" />
      <set property="children"/>
    </foreign-key>
  <table>

Und er Tabelle QWE fehlte der Primary Key:

  <table name="QWE" schema="dbo"> 
    <primary-key> 
       <key-column name="ID" /> 
    </primary-key> 
  </table> 
 

All das simuliert der Modellgenerierung von Hibernate eine Datenbank, die vorhandene Schwächen versteckt, ohne tatsächlich Änderungen an der Datenkbank zu machen (und damit evtl. bestehende Anwendungen zu gefährden). Diese Beispiele veranschaulichen nur einen Teil dessen, wie man mit Hibernate ein brauchbares Datenmodell für eine ‘legacy’ Datenbank erstellen kann. Ich kann als weitere Lektüre Chapter 6. Controlling reverse engineering empfehlen.

10.03.2012 - Zurück-Button unter Android

Für meine DRI-Log App wollte ich einen Button verwenden, der den Benutzer zurück zur vorherigen Activity bringt. Leider gibt es bei den unter Android verfügbaren Buttons keinen Zurückbutton. Apple’s iOS bringt einen Button mit, der an der linken Seite spitz zuläuft. Genau diese Form habe ich auch für Android gesucht und leider nicht gefunden.

Was tun, wenn man etwas sucht, dass es noch nicht gibt? Man macht es selber!

Ich habe dazu die Originalbuttons von Android in Inkscape als PNG importiert und bestmöglich nachgebaut. Anschließend habe ich sie spitz zulaufen lassen. Ich habe den Button im gleichen Stil wie Android 2.2 und 2.3 erstellt, da meine App bisher noch nicht für Android 3.0 oder neuer optimiert ist. Es wird ein Zurückbutton für diese Versionen folgen, wenn ich ihn benötige.

Achso: Falls mal jemand ein SVG von den Original-Android-Buttons benötigt, so findet er sie hier.

22.02.2012 - Hat eine DLL 32 oder 64 bit?

Ich musste gerade auf einem Windowssystem herausfinden, ob eine DLL 32 oder 64 bit hat. Jeder, der den Befehl file unter Linux kennt, sucht nach einer ebenso einfachen Möglichkeit unter Windows. Wenn man nach diesem Problem online sucht, findet man diverse absurde Lösungen … ein Perl-Skript, kurz mal Visual Studio installiern, etc.

Die einfachste Lösung fand ich beim ReactOS-Projekt, den Dependency Walker. Dieser zeigt einfach bei allen Symbolen der DLL ob sie 64 oder 32 Bit verwenden. So einfach kann es sein und der Dependency Walker muss nicht mal installiert werden.

02.01.2012 - Abstände bei Bildern in Listen (Android 2.3.3)

Ich verwende für eine App eine ListView. Diese ListView wird mit Layoutelementen befüllt, die aus einem Bild links und einem Text rechts bestehen. Soweit so trivial. Eine Zeile muss dabei nicht immer ein Bild haben und es ist natürlich viel schöner, das Nachladen der Bilder über einen Task zu machen. Dieser Task lädt die Bilder von einem Server herunter, der sie vorher auf die gewünschte Größe skaliert hat.

public class DownloadImageTask extends AsyncTask {

 private final ImageView image;

 public DownloadImageTask(ImageView image) {
  this.image = image;
 }

 protected Drawable doInBackground(String... url) {
  return HttpUtil.getDrawableFromUri(url);
 }

 protected void onPostExecute(Drawable drawable) {
  if (drawable != null) {
   image.setImageDrawable(drawable);
  }
 }
}

Damit erhält ist das übergebene Drawable in onPostExecute immer ein 120×120 Pixel großes Bild. Sobald dieser Code allerdings durchgelaufen ist, sind über und unter dem Bild viel zu große Abstände. Mit Hilfe der View Hierarchie-Perspektive der Android-Tools für Eclipse konnte ich feststellen, dass das Drawable mit dem Bild eine Breite von 50 Pixeln und eine Höhe von 120 Pixeln hatte. Das erklärte den Abstand. Aber woher genau kommt er? Sehen wir uns doch mal den Code für das Bild an:

 

Dieser Code legt die Breite auf 50 Pixel fest, allerdings nicht die Höhe. Es gibt zwei Lösungen für das Problem.

  • Entweder man setzt die Höhe fest auf 50 Pixel. Das funktioniert allerdings nur bei quadratischen Bildern.
  • Oder man fügt ein android:adjustViewBounds="true" in den ImageView-Code ein. Damit werden die Bilder korrekt auf max. 50 Pixel Breite unter Einhaltung der Aspektrate skaliert.

27.12.2011 - Unterschiede und Gemeinsamkeiten von Fedora und Gentoo

Ich habe mir vor etwas über einem Jahr auf meinem Laptop ein Ubuntu 10.4 LTS installiert. Mein Laptop muss nicht mit der neusten und tollsten Software laufen. Er muss stabil sein, weil ich damit arbeite. Ich will (und kann) mich nicht mit dem darunterliegenden Betriebssystem aufhalten. Allerdings hatte das System irgendwann beim Booten einen Kernelpanic. Da ich schnell wieder ein funktionierendes System benötigte, habe ich eine Gentoo stage3 in das existierende System eingespielt. Damit hatte ich ein stabiles System, was allerdings beim Installieren von Software aus offensichtlichen Gründen immer Probleme verursachte. Das System musste also wohl oder übel neu installiert werden.

Da ich einige Entscheidungen von Canonical bezüglich Ubuntu nicht vollständig teile (um mal die Schlagworte Unity, Ubuntu-One, CouchDB, Banshee zu nennen) und über Fedora sehr viel gutes gehört habe, wollte ich es mal ausprobieren.

Installation

Der Installer von Fedora (anaconda genannt) ist relativ elegant. Man kann mit minimalem Aufwand ein System installieren, dass direkt funktioniert. Das ist ein großer Vorteil gegenüber Gentoo. Die einzelnen Schritte zum Installieren eines Gentoo-Systems beherrsche ich zwar im Schlaf, aber sie sind aufwendiger (insbesondere wenn man nicht nur ein Kernsystem haben will, sondern auch X11, gnome und einen Browser). Die installierte Auswahl an Paketen ist grundsätzlich gut, bringt aber so manches Programm mit, was ich nicht benötigte.

Paketmanager

Gentoo bringt keinen graphischen Paketmanager mit. Es gibt aber diverse Ansätze um diesen zu etablieren, unter anderem PackageKit. Aus Ubuntu kannte ich synaptics, der mir wirklich gut gefiel. Fedora scheint keinen eigenen Paketmanager zu besitzen und statt dessen auch auf PackageKit zu setzen. Ich konnte mich zwar schnell wiederfinden, aber gpk-application ist bei weitem nicht so rund wie synaptics. Es ist schwierig die installierten Pakete zu finden, es wird zu viel wert auf die (leider meist schlecht gepflegte) Beschreibung anstelle des Paketnames gelegt und, was das größte Problem ist, die GUI versetzt sich des öfteren in einen Zustand, in dem nichts angeklickt werden kann (einfachstes Beispiel: nichts auswählen und Ausgewählte Pakete anklicken). Ich bin dazu übergegangen yum zu verwenden. Das Kommandozeilenprogramm lässt sich einfach bedienen und erfüllt seinen Zweck. Da ich unter Gentoo gewohnt bin mit emerge zu arbeiten, ist dies keine große Umstellung.

Software

Es gibt viel Software in Gentoo, die es nicht in Fedora gibt und umgekehrt. Interessant finde ich den Ansatz von Fedora, nur Software zuzulassen die aus den Quellen übersetzt wird. Das mag zwar theoretisch ein ganz toller Ansatz sein, ist aber in der Praxis kaum umzusetzen. Ich benötige beispielsweise den android-sdk. Gentoo stellt ein ebuild bereit, um das Binärpaket nach /opt zu installieren. Mit der richtigen Gruppenberechtigung darf der normale Nutzer auch neue API-Versionen installieren. Super. Unter Fedora wollte ich ebenfalls diesen Luxus. Theoretisch kann man sich den Android SDK selbst bauen (so weit ich weiß sollte alles daran Open-Source sein), aber wieso auf die vorbereiteten Pakete von Google verzichten? Ich bin dazu übergegangen aus Gentoo-ebuilds mir rpm’s für Fedora zu erstellen. Beide haben eine gewisse Ähnlichkeit obwohl ebuilds meines Erachtens bedeutend luxuriöser sind. Aber dazu ein andermal mehr.

Fazit

Gentoo bietet mit den ebuilds (und zugehörigen USE-Flags) eine perfekte Möglichkeit ein System genau so zu bauen, wie man es benötigt. Aber: es braucht Zeit. Fedora stellt ein sehr gut nutzbares System zur Verfügung. Es ist bei weitem nicht so “poliert” wie Ubuntu. Es ist auch stärker auf Geeks ausgelegt (z.B. durch Verwendung von SELinux per Default, was nicht das einfachste Sicherheitsframework ist). Alles in Allem ist es aber absolut brauchbar und nach ein paar Konfigurationseinstellungen (SELinux deaktivieren, Themes installieren, Fonts anpassen, PS1 anpassen) sehr gut zu benutzen.

19.12.2011 - mod_jk und SELinux

Tomcat cluster hinter einem Apache HTTPd

Um einen oder mehrere Apache Tomcats hinter einen Apache HTTPd zu betreiben, gibt es verschiedene Protokolle. Ein häufig genutztes Protokoll ist das AJP/1.3-Protokoll (Apache JServ Protocol), da es Load-Balancing unterstützt. Da die SSL-Terminierung bereits im Webserver durchgeführt wird, sollte dieses Betriebsszenario nur verwendet werden, wenn der Kommunikationskanal zwischen HTTPd und Tomcat sicher ist.

mod_jk

mod_jk

Das AJP/1.3-Protokoll unterstützt Tomcat von hause aus, für HTTPd wird es von mod_jk implementiert. Dieses Setup ist relativ einfach und wird von vielen Firmen so betrieben. Soweit die Theorie. In der Praxis wollte dies auf einer Distribution mit SELinux nicht funktionieren und ich fand folgenden Logeintrag:

connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=13)

Die Debug-Ausgaben von mod_jk ergaben, dass eine Verbindung zu 127.0.0.1:8009 fehlschlug. Zuerst hatte ich IPv6 in Verdacht. Also habe ich es erstmal deaktiviert:

echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6

Dies brachte keine Besserung. Der Service lief jetzt zwar unter IPv4, telnet klappte, aber der Apache HTTPd wollte sich trotzdem nicht verbinden. Dann fand ich folgenden Logeintrag

[error] init_jk::mod_jk.c (3235): Initializing shm:/var/log/httpd/jk-runtime-status.16551 errno=13. Load balancing workers will not function properly.

Eine kurze Recherche ergabe, dass SELinux dazwischen funkt. Ich weiß nicht, warum SELinux bei manchen Distribution per Default aktiviert ist. Es zwar für die Sicherheit gut, aber bisher war die Toolunterstützung nicht leicht eingängig. Für einen Einsteiger ist es sehr schwierig, ohne einfache Übersicht (egal ob GUI oder Log-Datei) den Fehler zu finden und einzugrenzen. Meine Lösung ist es in der Datei ‘/etc/selinux/config’ folgende Zeile einzufügen.

SELINUX=disabled

Anschließend funktioniert alles. Hinweis: Damit wird SELinux vollständig abgeschaltet. Für ein Entwicklungssystem im sicheren Netz ist dies vertretbar, diese Lösung sollte auf keinen Fall auf einem produktiv genutzen Server genutzt werden.

23.11.2011 - MyPaint Berg

Kürzlich habe ich mal wieder Lust dazu bekommen, mein Grafiktablett auszuprobieren. Daher habe ich diese kleine Szene gemalt:

Handpainted mountains

Es ist das erste Mal, dass ich mit dem Tablet tatsächlich ein ansehnliches Ergebnis produziert habe. Das hat mit selbst etwas überrascht und ich bin dem etwas nachgegangen. Bisher habe ich das dem Table beiliegende Corel Essential 2 oder Gimp verwendet. Beide sind zwar nette Spielereien für Tablets, aber kommen darüber nicht hinweg. Da ich durch Zufall von MyPaint gehört hatte, wollte ich das mal ausprobieren. Ich muss sagen: Ich bin sehr zufrieden, denn die guten mitgelieferten Brushes sind der Grund, warum ich dieses Mal mehr als ein “Hallo, dies ist ein Test” gemalt habe. Und natürlich, dass ich vor Kurzem in die Bob Ross DVD rein gesehen habe ;-).

15.11.2011 - Weitere Details zu ADT und Maven

Da ich bereits mehrfach gefragt wurde, wie man mit Maven und ADT ein Projekt multimandandenfähig macht (d.h. aus einem Sourcebaum entstehen mehrere Apps), fasse ich das hier mal kurz zusammen.

Grundsätzlich benötigt man die Maven-Struktur für ein Android Projekt. Diese sieht wie folgt aus:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>de.egore911.mobile</groupId>
 <artifactId>test</artifactId>
 <version>0.1-SNAPSHOT</version>
 <packaging>apk</packaging>
 <name>${project.artifactId}</name>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
   <groupId>com.google.android</groupId>
   <artifactId>android</artifactId>
   <version>2.2.1</version>
   <scope>provided</scope>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <groupId>com.jayway.maven.plugins.android.generation2</groupId>
    <artifactId>android-maven-plugin</artifactId>
    <version>3.0.0-alpha-14</version>
    <configuration>
     <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
     <assetsDirectory>${project.basedir}/assets</assetsDirectory>
     <resourceDirectory>${project.basedir}/res</resourceDirectory>
     <nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>
     <sdk>
      <platform>8</platform>
     </sdk>
     <deleteConflictingFiles>true</deleteConflictingFiles>
     <undeployBeforeDeploy>true</undeployBeforeDeploy>
    </configuration>
    <extensions>true</extensions>
   </plugin>

   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>

  </plugins>
 </build>

Ich werde an dieser Stelle nicht auf die einzelnen Teile eingehen. Es geht jetzt darum, wie man Resources austauschen kann. Dazu verwendet man in Maven Profile. Ich verwende z.B. ein Profil namens “demo”.

<profile>
 <id>demo</id>
 <activation>
  <property>
   <name>config</name>
   <value>demo</value>
  </property>
 </activation>
 <build>
  <plugins>
   <plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.5</version>
    <executions>
     <execution>
      <id>copy-assets</id>
      <phase>initialize</phase>
      <goals>
       <goal>copy-resources</goal>
      </goals>
      <configuration>
       <outputDirectory>${basedir}/assets</outputDirectory>
       <resources>
        <resource>
         <directory>${basedir}/templates/assets/demo</directory>
         <filtering>false</filtering>
        </resource>
       </resources>
       <overwrite>true</overwrite>
      </configuration>
     </execution>
     <execution>
      <id>copy-res</id>
      <phase>initialize</phase>
      <goals>
       <goal>copy-resources</goal>
      </goals>
      <configuration>
       <outputDirectory>${basedir}/res</outputDirectory>
       <resources>
        <resource>
         <directory>${basedir}/templates/res/demo</directory>
         <filtering>false</filtering>
        </resource>
       </resources>
       <overwrite>true</overwrite>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
</profile>

Hierbei sind zwei Dinge zu beachten:

  1. Das Kopieren der Ressourcen muss vor der Ausführung das Android-Plugins passieren. Da das Android-Plugin in der Phase “generate-sources” ausgeführt wird, habe ich “initialize” als Phase gewählt (Warum erschließt sich bei der Betrachtung des Maven Livecycle).
  2. Per Default überschreibt das maven-resource-plugin nicht bestehende Resourcen, wenn diese neuer sind. Dies ist für den gegebenen Anwendungsfall natürlich unpraktisch.

Damit kann jetzt jeder seine App auch als Demo ausliefern. Es bleibt dem Entwickler überlassen, ob er die Vollversion in den res und assets-Ordnern pflegt oder diese auch als Profile realisiert. Ich habe letzteres verwendet, damit ich mir nicht aus Versehen teile der Demo in die Vollversion stecke (oder umgekehrt). Man sollte in diesem Fall darauf achten, dass die Daten nicht ins Versionskontrollsystem eingecheckt werden. Dies kann dann allerdings zur Folge haben, dass wenn kein Profil aktiv ist, die Daten fehlen und der Android-Buildprozess fehlschlägt. Als Lösung bietet sich an, entweder ein Profile auf “activeByDefault” zu stellen, oder in der Entwicklungsumgebung das Profil zu aktivieren.

02.11.2011 - Android und Maven

Man kann mit Eclipse und den dazugehörigen ADT sehr elegant für Android entwickeln. Allerdings bin ich darüber gestolpert, dass man damit nicht ohne weiteres “Demos” einer vollwertigen Applikation (d.h. ein APK, dass gewisse Einschränkungen gegenüber einer Vollversion der selben Software hat) aus den gleichen Sourcen erzeugen kann.

Es wäre evtl. möglich dass in den Ant-basierten Build einzubinden, allerdings habe ich gleiches bereits für Maven konzipiert und will das Rad nicht neu erfinden. Bei einer kurzen Internetrecherche bin ich über das android-maven-plugin gestolpert. Es erlaubt einem, dass Ant-basierte Buildsystem durch Maven zu ersetzen. Nachdem ich diesen Schritt vollzogen hatte, ließ sich unter Verwendung der Maven-Profiles problemlaus eine Demo erzeugen.

22.09.2011 - Nachverfolgung eines Upstream-Projekts mit git

Bei der Softwareentwicklung sollte man möglichst nie das Rad neu erfinden. Dies gibt beispielsweise schon das DRY-Prinzip vor. Als Erweiterung des Prinzips sollte man sich nicht nur seine eigene Arbeit nicht wiederholen, sondern auch nicht die Arbeit von anderen. Daher werden in allen Softwareprojekten andere Softwareprojekte als Abhängigkeiten verwendet. Es kommt bei externen Abhängigkeiten manchmal zu dem Effekt, dass diese minimale Anpassungen benötigen.

Anpassungen an externen Projekten

Wir nehmen ein beliebiges Open Source Projekt, dass man zuerst anpassen muss, bevor man es benutzen kann. (Hinweis: Bitte vor der Anpassung die Lizenz des Projekts prüfen!). Wir nehmen einen Softwarestand des entsprechenden Projektes, passen den Stand an und verwenden die angepasste Abhängigkeit. Das Problem dabei: Wie übernimmt man seine Änderungen in neue Versionen?

Die Lösung dazu bietet sich im Versionskontrollsystem git. Die Idee ist sehr einfach, erleichtert das Vorgehen aber massiv. Zuerst importiert man den initialen Stand der Software (im unteren Beispiel “Release 1.0″). Diesen Stand brancht man in 2 Richtungen ab:

  1. Der Zweig mit dem offiziellen Stand der Software (upstream genannt)
  2. Der Zweig mit lokalen Änderungen (master)

Jetzt können im “master” Branch wie gewohnt die notwendigen Anpassungen vorgenommen werden. Sobald eine neue Version der Software erscheint wechselt man in den “upstream” Branch und importiert die neue Version. Sobald man mit git den Branch “upstream” wieder in den “master” merged, erhält man eine automatisch gepatchte Version mit den vorigen Änderungen. Eine meist enorme Zeitersparnis.

git_track_upstream

 

Hinweis: Natürlich ist es möglich (sofern das externe Softwareprojekt git als Versionskontrollsystem verwendet), den händische Import zu vermeiden. Der Arbeitsablauf selbst ändert sich dadurch aber nicht.

Unsauberer Start

Aber was macht man, wenn man erst zu spät feststellt, dass man dieses Vorgehen mit git so einfach ist? Nehmen wir an, wir haben einen Stand des Upstream-Projekts importiert und im gleichen Branch unsere Änderungen gemacht:

git_unclean_track_upstream_pre

Ganz einfach: Man erstellt den Branch “upstream” indem man ihn vom “master” abspaltet. Jetzt wechselt man in diesen Branch, löscht den gesamten Inhalt und importiert den offiziellen Stand der Software (der zu dem Stand im “master” Branch passt, d.h. wenn master eine angepasst Version von 1.0 ist, würde man die offizielle Version 1.0 importieren). Jetzt würde bei einem Merge natürlich das schlimmste Chaos entstehen. Daher muss man git ein wenig helfen. Wir behaupten einfach, dass alles, was derzeit im “upstream” Branch steckt, bereits zurück in den “master” gemerged wurde:

git checkout master
git merge -s ours upstream

git_unclean_track_upstream_merge

Damit kann man dann genauso wie oben beschrieben arbeiten, also in “upstream” immer den aktuellen Stand importieren und in den master mergen.

git_unclean_track_upstream_post

Dieser kleine Trick reduziert die Dauer von mehreren Stunden des händischen Vergleich der Änderungen auf wenige Minuten durch diese Automatisierung. Hinweis: Ein anschließendes Testen des angepassten Softwarestand ist allerdings trotzdem notwendig!

Änderungen an das externe Projekt zurückgeben

Grundsätzlich ist dieses Vorgehen einfach, aber aufwendig (je nach dem wie häufig das Einspielen einer neues Upstream-Version vorkommt). Ich versuche immer, die Änderungen an das externe Projekt zurückzugeben, selbst wenn die Lizenz dies nicht erfordert. Dies reduziert den lokalen Aufwand, stellt die (vermutlich hilfreiche) Anpassung allen anderen Nutzern zur Verfügung und motiviert die Betreuer des externen Projekts.

25.08.2011 - ArrayIndexOutOfBoundsException im maven-project-info-reports-plugin

Maven stellt verschiedene Werkzeuge im Umfeld von Java-Projekten zur Verfügung. Eines der Features ist die automatische Seitengenerierung mittels dem Maven-Goal site.

Ich hatte heute ein Problem mit der Seitengenerierung, bei der ich unter Anderem das maven-project-info-reports-plugin verwende. Dieses Plugin erzeugte bei jeden Aufruf eine ArrayIndexOutOfBoundsException im maven-project-info-reports-plugin, die nicht direkt zu deuten war:

java.lang.ArrayIndexOutOfBoundsException: 1
    at org.apache.maven.doxia.module.xhtml.XhtmlSink.tableCell(XhtmlSink.java:791)
    ....

Nach kurzer Recherche stellte sich heraus, dass die Version des maven-site-plugins zu alt war. Um eine neuere Version in einem Projekt zu verwenden, kann folgendes in die pom.xml des Projekts eingetragen werden:

 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-site-plugin</artifactId>
    <!-- Version 2.3 oder neuer wird für das maven-project-info-reports-plugin benötigt -->
    <version>2.3</version>
   </plugin>
  </plugins>
 </build>

26.07.2011 - Brother DCP-585CW Scanner unter Linux

Nachdem mein alter Druckern leider kaputt gegangen ist, wurde er durch einen Netzwerkdrucker ersetzt. Damit ist es möglich, von jedem Rechner im lokalen Netzwerk zu drucken. Meine Wahl fiel auf Grund des guten Preis-Leistungs-Verhältnis auf einen Brother DCP-585CW. Dieser verfügt neben einem WLAN-Anbindung und einem Scanner auch noch Linux-Treiber.

Daher habe ich versucht den Scanner des Brother unter Linux zu benutzen. Brother stellt direkt offizielle Treiber für Linux zur Verfügung und beschreibt im Detail, wie man den Treiber installiert. Leider klappte die Verbindung zum Scanner nicht auf Anhieb. Die Anleitung von Ubuntuusers brachte keine Besserung, aber die Lösung fand ich im Gentoo Forum:

In der /etc/sane.d/dll.conf fehlte bei mir die folgende Zeile:

brother3

Danach funktionierte der Scanner endlich. Allerdings musste ich dann herausfinden, dass die Optionen von “scanimage” wohl proprietär sind. Der alte Scanner kannte ‘–mode=Lineart’, der neue Scanner verwendet ‘–mode=”Black & White”‘.

07.07.2011 - Postfix Relay pro Absender

Für den zuvor beschriebenen Mailserver wird neben dem Empfang natürlich auch der Versand benötigt. Bisher hatte ich meine E-Mail-Clients so eingestellt, dass sie beim Versand direkt an den E-Mail-Server der E-Mail-Adresse senden. Dies hat den Nachteil, dass man in jedem Client die Passwörter neu eingeben muss. Daher war die Idee einen zentralen Server auf Postfix-Basis auf dem gleichen Rechner wie dem IMAP-Server zu betreiben, der dann SMTP-Relay macht.

Dieses Setup hatte ich vor mehreren Jahren bereits ausprobiert und hatte die Annahme, dass die Einrichtung genauso funktioniert. Allerdings ist SMTP-Relay heute auf Grund des Spam-Aufkommens bedeutend restriktiver. So erlaubt z.B. der Mailserver der Domain “christophbrill.de”, das ausschließlich E-Mail mit Absenderadressen von “@christophbrill.de” weitergereicht werden. Da ich auch im Besitz einer Freemail-Adresse bin, würden diese E-Mail immer abgelehnt. Also war die einzige Option einen Relay pro Absender zu verwenden. Glücklicherweise kann Postfix dies von Hause aus.

In der Datei /etc/postfix/main.cf wird zusätzlich folgendes benötigt

smtp_sender_dependent_authentication = yes
sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relay
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_mechanism_filter = plain, login

Damit wird das Relaying pro Sender aktiviert. Jetzt müssen natürlich noch die Absender und relayhosts konfiguriert werden. In der Datei /etc/postfix/sender_relay stehen dann Einträge der Form

emailadress1@irgend-ein-provider.de   smtp.irgend-ein-provider.de

und in der /etc/postfix/passwd stehen dann die zugehörigen Zugangsdaten

emailadress1@irgend-ein-provider.de   benutzername:passwort

Bei mir sind dabei folgende Fehler aufgetreten, die man in /var/log/mail.err:

fatal: open database /etc/postfix/sender_relay.db: No such file or directory

Das passiert dann, wenn man postmap hash:/etc/postfix/sender_relay noch nicht aufgerufen hat

Relay access denied

Dieser Fehler tritt auf, weil Postfix per Default in mynetworks nicht mein privates Netzwerk stehen hat und in der Standardkonfiguration nur Hosts aus dem privaten Netzwerk einen Relay machen dürfen.

SASL authentication failed; .... no mechanism available

Dieser Fehler tritt auf, weil Postfix per Default keinen SASL-Mechanismus vorgibt. Mit Hilfe des Parameters smtp_sasl_mechanism_filter lässt sich dies leicht steuern.

Alles in Allem war das SMTP-Relay in weniger als einer halben Stunde eingerichtet und funktioniert jetzt problemlos. Meine E-Mail Clients “reden” jetzt nur noch mit dem zentralen Server, was den Konfigurationsaufwand pro Arbeitsplatz minimiert (ok, es ist nur Desktop-Rechner und ein Netbook, aber es geht ja ums Prinzip ;-).

28.05.2011 - Dovecot und fetchmail ohne procmail

Ich habe vor kurzem ein IMAP-Mailserver auf Basis von Dovecot installiert. Dieser dient als Ersatz für mein vorheriges Setup auf Basis von Courier-IMAPd + Procmail. Der Hauptbewegrund war Sieve, eine modernes Mail-Sortier-und-Filter-System.

Bisher funktionierte mein Server so: fetchmail ruft die E-Mails ab, übergibt sie an den SMTP-Server postfix, der übergibt sie an procmail (der sie mit Hilfe der .procmailrc sortiert) und sie können dann über courier-imapd abgerufen werden. Das klingt nicht nur kompliziert, sondern ist es auch.

Jetzt funktioniert es einfacher: fetchmail ruft die E-Mails weiterhin ab, übergibt sie aber an dovecot (an den deliver LDA um genau zu sein) und wir sind fertig. Kürzer. Weniger fehleranfällig. Konfigurierbar über die managesieve-Erweiterung für Thunderbird (was der Hauptbeweggrund war, um von .procmailrc weg zu kommen).

Eigentlich sind dafür relativ wenig Konfigurationsoptionen notwendig:

1.) In der dovecot.conf im protocol lda as Sieve-Plugin aktivieren.

2.) In die /etc/fetchmailrc

mda "HOME=/home/%T /usr/bin/sudo -u %T /usr/lib/dovecot/deliver"

eintragen

3.) Mittels visudo folgenden Filter eingeben:

fetchmail ALL=(ALL) NOPASSWD:/usr/lib/dovecot/deliver

Der einentliche Trick dabei ist es, dass fetchmail bei mir als globaler Service ausgeführt wird, und zwar als eigener Benutzer ‘fetchmail’. Ein direkter Aufruf von deliver allerdings hat zur Folge, dass die E-Mails im Ordner des Fetchmail-Benutzers landen und nicht dem in der fetchmailrc konfigurierten(!). Diese kleine Information ist extrem entscheidend für das erfolgreiche Abrufen von E-Mails und hat mich ein paar Stunden des Grübelns gekostet. Jetzt funktioniert alles und ich kann endlich wieder E-Mails abrufen… und vor allem sortieren :-)

30.09.2010 - Ogreopcode und Ogre 1.7

Ich bin derzeit mal wieder dabei an Opengate rumzuexperimentieren. Dazu benötige ich ogreopcode, einen Wrapper der Ogre (eine 3D Engine) mit Opcode (einer Bibliothek zur Kollisionserkennung). Allerdings war dieser nicht mit der neuesten Ogre Version (1.7.1) kompatibel. Daher habe ich folgende Ändernungen gemacht:

===================================================================
--- src/IOgreCollisionShape.cpp (revision 417)
+++ src/IOgreCollisionShape.cpp (working copy)
@@ -264,7 +264,7 @@
                if(!mHasCostumTransform)
                {
                        getParentSceneNode()->_update(true, true);
-                       getParentSceneNode()->getWorldTransforms(&mFullTransform);
+                       mFullTransform = getParentSceneNode()->_getFullTransform();
                }
                return mFullTransform;
        }
Index: src/OgreBoxCollisionShape.cpp
===================================================================
--- src/OgreBoxCollisionShape.cpp       (revision 417)
+++ src/OgreBoxCollisionShape.cpp       (working copy)
@@ -204,7 +204,7 @@

                calculateSize();

-               mParentNode->getWorldTransforms(&mFullTransform);
+               mFullTransform = mParentNode->_getFullTransform();
                //mFullTransform = mParentNode->_getFullTransform();

                return true;
Index: src/OgreMeshCollisionShape.cpp
===================================================================
--- src/OgreMeshCollisionShape.cpp      (revision 417)
+++ src/OgreMeshCollisionShape.cpp      (working copy)
@@ -287,8 +287,7 @@
                }

                mParentNode = mDummyNode;
-               //mFullTransform = mEntity->getParentSceneNode()->_getFullTransform();
-               mParentNode->getWorldTransforms(&mFullTransform);
+               mFullTransform = mParentNode->_getFullTransform();
                return rebuild();
        }

Das ist einer der großen Vorteile von Open Source: Wenn es nicht funktioniert, hat man die Chance herauszufinden warum nicht.

Copyright © christophbrill.de, 2002-2015.