<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>BeagleOutOfBoundsException &#187; Software Entwicklung</title>
	<atom:link href="http://www.nw-software.com/category/software-entwicklung/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.nw-software.com</link>
	<description>Ein Beagle durchbricht die Grenzen schneller als ein Index.</description>
	<lastBuildDate>Wed, 31 Aug 2011 08:44:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>GWT: Code Splitting mit ProviderBundle</title>
		<link>http://www.nw-software.com/2011/08/gwt-code-splitting-mit-providerbundle/</link>
		<comments>http://www.nw-software.com/2011/08/gwt-code-splitting-mit-providerbundle/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 08:44:52 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[codesplit]]></category>
		<category><![CDATA[codesplitting]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[gwtp]]></category>
		<category><![CDATA[mvp]]></category>
		<category><![CDATA[presenter]]></category>
		<category><![CDATA[providerbundle]]></category>
		<category><![CDATA[proxy]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=263</guid>
		<description><![CDATA[Möchte hier mal wieder kurz was notieren, damit ich es selber nicht vergesse ;) Code Splitting von GWT ist eine tolle Sache. Da ich kein Guru bin werde ich mal versuchen das in meinen laienhaften Worten zu erklären. GWT liefert alles was man programmiert an den Client aus, da das teilweise sehr viel sein kann [...]]]></description>
			<content:encoded><![CDATA[<p>Möchte hier mal wieder kurz was notieren, damit ich es selber nicht vergesse ;)</p>
<p>Code Splitting von GWT ist eine tolle Sache. Da ich kein Guru bin werde ich mal versuchen das in meinen laienhaften Worten zu erklären. GWT liefert alles was man programmiert an den Client aus, da das teilweise sehr viel sein kann wurde Code Splitting eingeführt. Presenter, deren Proxies mit der ProxyCodeSplit Annotation versehen sind werden erst vom Server nachgeladen, sobald diese das erste mal mit Inject verwendet werden. Dadurch kann der Client den GWT Code schneller laden, da dort nur die notwendigen Sachen hinterlegt werden. Der Code von Presentern die nicht von Anfang an benötigt werden, wird also erst bei deren erster Verwendung vom Server zum Client übertragen.</p>
<p>Diese Möglichkeit lässt es sinnvoll erscheinen, im gesamten Anwendungscode bzw. soviel wie möglich, Code Splitting zu verwenden. Ein zusätzlicher Vorteil ist, die Funktionalität der einzelnen Klassen kann schön klein gehalten werden, da der Presenter notwendige Klassen injiziert bekommen kann. Die Sache hat nur einen Haken: Das Nachladen benötigt erstens etwas Zeit und zweitens muss für jeden gesplitteten Code eine Anfrage an den Server gestellt werden. Jede Anfrage benötigt durch den Overhead noch zusätzlich Zeit, außerdem bearbeiten Browser i.d.R. nur zwei Anfragen an eine Domain gleichzeitig. Wird also ein Presenter angezeigt, der selber mehrere gesplittete Teile enthält, kann dies den Benutzereindruck trüben.</p>
<p>Die Lösung hierfür haben die Entwickler von GWT mit Provider Bundles geschaffen. In einem ProviderBundle legt man alle zusammenhängende Teile fest, die gemeinsam nachgeladen werden sollen. In der Anwendung an der ich gerade arbeite verwenden wir das, um bestimmte Aktionen auszulagern, die von mehreren Presentern verwendet werden können. Dadurch kann jede Aktion in einem übersichtlichen Class File programmiert werden das zudem noch in einer entsprechenden Package Hirarchie für eine leichtere Wartbarkeit abgelegt werden kann. Für jeden Presenter gibt es dann ein ProviderBundle das festlegt, welche Actions mit dem Presenter geladen werden sollen. Code Splitting und Provier Bundles können aber auch anders verwendet werden.</p>
<p>Die GWT bzw. GWTP Dokumentation erklärt das Vorgehen leider (noch) nicht. Für viele mag sich die Verwendung auch aus den Kommentaren der <a href="http://code.google.com/p/gwt-platform/source/browse/gwtp-core/gwtp-clients-common/src/main/java/com/gwtplatform/common/client/ProviderBundle.java">ProviderBundle</a> Klasse erschließen, ich hatte hierbei jedoch einige Anlaufschwierigkeiten. Daher möchte ich hier mal kurz die Vorgehensweise skizzieren:</p>
<pre class="brush: java">
public class ShowGalleriesA extends UiAction {
	...
}
</pre>
<p>Das ist die Action Klasse. Die Implementierung ist für den Mechanismus nicht wichtig, daher hab ich sie weg gelassen. Man muss hier eigentlich nur beachten, das es nichts zu beachten gibt ;)<br />
Es ist eine ganz gewöhnliche Java Klasse, es sind keine Annotations oder ähnliches notwendig (außer natürlich das was für die Funktion der Klasse benötigt wird). Auch UiAction, die Basisklasse, enthält nichts was mit dem Code Splitting zu tun hat.</p>
<pre class="brush: java">
public class DashboardPr extends PlacePresenter<DashboardIf, DashboardPr.MyProxy> {

	@ProxyCodeSplitBundle(bundleClass = DashboardBundle.class, id = DashboardBundle.ID_DashboardPresenter)
	@NameToken(NameTokens.dashboard)
	public interface MyProxy extends ProxyPlace<DashboardPr> {
	}

	@Inject
	public DashboardPr(
            DashboardIf view,
            MyProxy proxy,
            final ShowGalleriesA aShowGalleries) {
		super(view, proxy);

		setActions(aShowGalleries);
	}
	...
}
</pre>
<p>Der Presenter hingegen ist schon interessanter. Die normalerweise verwendete @ProxyCodeSplit Annotation wird durch @ProxyCodeSplitBundle ersetzt. In den Parametern der Annotation muss angegeben werden welche Klasse das Bundle definiert und welche ID daraus der des annotierten Proxies entspricht. Siehe Definition des Provider Bundles:</p>
<pre class="brush: java">
public class DashboardBundle extends ProviderBundle {
	public final static int ID_DashboardPresenter = 0;
	public final static int ID_ActionShowGalleries = 1;
	public final static int BUNDLE_SIZE = 2;

	@Inject
	public DashboardBundle(
			final Provider<DashboardPr> dashboardPresenter,
			final Provider<ShowGalleriesA> actionShowGalleries) {
		super(BUNDLE_SIZE);

		providers[ID_DashboardPresenter] = dashboardPresenter;
		providers[ID_ActionShowGalleries] = actionShowGalleries;
	}
}
</pre>
<p>Sollte eigentlich relativ selbsterklärend sein ;)<br />
Alle Teile des Bundles (die also zusammen geladen werden sollen) werden mit @Inject dem Konstruktor übergeben und in einem Feld providers der Basisklasse ProviderBundle hinterlegt. Wichtig ist hierbei, dass die Größe des providers Array dem Superklassen Konstruktor richtig mitgegeben wird. Am einfachsten macht man das über die gezeigten (und auch von Google empfohlenen) statischen Konstanten mit denen man dann auch auf die jeweiligen IDs der einzelnen Teile des Bundles verweisen kann (siehe Parameter der @ProxyCodeSplitBundle Annotation in der Presenter Klasse).</p>
<p>Nun müssen im Ginjector die AsyncProvider für die Einzelteile definiert werden, damit das Injizieren funktioniert:</p>
<pre class="brush: java">
public interface MyGinjector extends Ginjector {
	...
	AsyncProvider<DashboardPr> getCustomerDetailPresenter();
	AsyncProvider<ShowGalleriesA> getShowGalleriesAction();
	AsyncProvider<DashboardBundle> getDashboardBundle();
	...
}
</pre>
<p>Und schon wird die Aktion automatisch mit dem Presenter geladen. Einfach oder? ^^</p>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=263&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2011/08/gwt-code-splitting-mit-providerbundle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objekte mit Events serialisieren mit dem BinaryFormatter</title>
		<link>http://www.nw-software.com/2011/07/objekte-mit-events-serialisieren-mit-dem-binaryformatter/</link>
		<comments>http://www.nw-software.com/2011/07/objekte-mit-events-serialisieren-mit-dem-binaryformatter/#comments</comments>
		<pubDate>Thu, 07 Jul 2011 07:16:35 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[binaryformatter]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[deserialize]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[serialize]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=256</guid>
		<description><![CDATA[In meinem aktuellen Projekt muss ein recht komplexer Objektbaum in eine Datei serialisiert werden, um eine Speichern und Laden Funktion bieten zu können. Da es im Modell auch zirkuläre Referenzen gibt und ich im vorliegenden Fall nichts von SOAP halte, verwende ich den BinaryFormatter für diese Aufgabe (obwohl das von mir beschriebene Problem ziemlich sicher [...]]]></description>
			<content:encoded><![CDATA[<p>In meinem aktuellen Projekt muss ein recht komplexer Objektbaum in eine Datei serialisiert werden, um eine Speichern und Laden Funktion bieten zu können. Da es im Modell auch zirkuläre Referenzen gibt und ich im vorliegenden Fall nichts von SOAP halte, verwende ich den BinaryFormatter für diese Aufgabe (obwohl das von mir beschriebene Problem ziemlich sicher auch auf andere Formatter zutreffen wird).</p>
<p>Aber nun zum eigentlichen Problem: das alle Klassen die serialisiert werden sollen das Attribut Serializable benötigen sollte allen klar sein. Was ich jedoch schmerzhaft feststellen musste ist, dass auch jede Klasse die sich für ein Event einer zu serialisierenden Klasse registriert serialisierbar sein muss. Denn die Events werden mit serialisiert, sodass sie nach der Deserialisierung weiter verknüpft bleiben. Bei den Kollegen von <a href="http://www.sanity-free.org/113/csharp_binary_serialization_oddities.html">Sanity Free Coding</a> wird das ganze auch noch ausführlicher erläutert und auch ein Lösungsvorschlag gegeben.</p>
<p>Der dort beschriebene Ansatz birgt allerdings auch ein paar Stolper-fallen: in dem Beispiel wird das Event nämlich nie mitserialisiert, also auch nicht, wenn die auf das Event lauschende Klasse serialisierbar ist. In meinem Projekt ist es so, dass der Objektbaum über Listen mit Parent Child Funktion verfügt. Darüber kann im Baum hoch und runter navigiert werden. Außerdem bieten die Listen Events, die bei Änderung daran gefeuert werden z.B. wenn ein neues Objekt hinzugefügt oder gelöscht wird. Manche Objekte im Baum müssen wissen, wenn sich was im Baum an anderer Stelle geändert hat, um sich selbst zu aktualisieren und den Baum somit konsistent zu halten. Daher registrieren sie sich für die Changed Events. Diese Events sollten also auch nach der Deserialisierung wieder hergestellt sein. Andererseits registrieren sich auch Oberflächensteuerelemente für die Changed Events, damit die Oberfläche dementsprechend aktualisiert werden kann. Diese Events werden beim Aufbau der Oberfläche aber ohnehin jedesmal neu verdrahtet, müssen also nicht serialisiert werden. </p>
<p>Eine Möglichkeit wäre nun, für jedes Objekt im Modell ISerializable und einen Deserialisierungskonstruktor zu implementieren und die komplette De-/Serialisierung selber zu machen. Dabei könnte man im Deserialisierungskonstruktor die Eventzuordnung ebenfalls jedesmal neu verdrahten. Was aber bei komplexen Objekten wenig Spass macht und bei Änderungen am Objekt jedesmal mit angepasst werden muss. Mein Ansatz ist eine Erweiterung der von Sanity Free Coding vorgeschlagenen Methode. Beim Registrieren der Events in der add sowie beim Deregistrieren in der remove Methode wird das Event Target per Reflection überprüft. Ist das Target serialisierbar, wird das Event einem privaten event zugeordnet, das serialisiert wird. Ist das Target nicht serialisierbar, wie z.B. unsere Oberflächensteuerelemente, wird das event Feld mit vorangestelltem [NonSerializable] verwendet. Genial einfach und einfach genial. Hier noch etwas Code um sich das besser vorstellen zu können:</p>
<pre class="brush:csharp;">
[NonSerialized]
private EventHandler&lt;ParentChildListChangedEventArgs&lt;C&gt;&gt; changedNonSerializable;
private EventHandler&lt;ParentChildListChangedEventArgs&lt;C&gt;&gt; changedSerializable;

public event EventHandler&lt;ParentChildListChangedEventArgs&lt;C&gt;&gt; Changed
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    add
    {
        if (value.Target.GetType().IsSerializable)
            changedSerializable += value;
        else
            changedNonSerializable += value;
    }
    [MethodImpl(MethodImplOptions.Synchronized)]
    remove
    {
        if (value.Target.GetType().IsSerializable)
            changedSerializable -= value;
        else
            changedNonSerializable -= value;
    }
}
</pre>
<p>gefeuert wird das ganze dann wie folgt:</p>
<pre class="brush:csharp;">
protected virtual void OnChanged(ParentChildListChangedEventArgs&lt;C&gt; e)
{
    if (changedNonSerializable != null) changedNonSerializable(this, e);
    if (changedSerializable != null) changedSerializable(this, e);
}
</pre>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=256&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2011/07/objekte-mit-events-serialisieren-mit-dem-binaryformatter/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Windows Forms: Entity Framework Datenbindung, Enums und ComboBoxen</title>
		<link>http://www.nw-software.com/2011/02/windows-forms-entity-framework-datenbindung-enums-und-comboboxen/</link>
		<comments>http://www.nw-software.com/2011/02/windows-forms-entity-framework-datenbindung-enums-und-comboboxen/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 09:44:59 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=232</guid>
		<description><![CDATA[Wer den Support von Enums im Entity Framework auch vermisst, oder aber einfach nur in der Datenbank mit Integerwerten arbeiten möchte oder vielleicht sogar muss, weil das Datenbankdesign nicht geändert werden kann, der hat zwei Möglichkeiten für eine funktionierende Datenbindung: Entweder werden die Entitäten in den partiellen Klassen um die Enum Eigenschaften erweitert. Dieser Ansatz [...]]]></description>
			<content:encoded><![CDATA[<p>Wer den Support von Enums im Entity Framework auch vermisst, oder aber einfach nur in der Datenbank mit Integerwerten arbeiten möchte oder vielleicht sogar muss, weil das Datenbankdesign nicht geändert werden kann, der hat zwei Möglichkeiten für eine funktionierende Datenbindung:</p>
<p>Entweder werden die Entitäten in den partiellen Klassen um die Enum Eigenschaften erweitert. Dieser Ansatz bringt allerdings auch einige Fallstricke mit sich. Eine gute Umsetzung und genauere Erläuterungen findet ihr bei <a href="http://landman-code.blogspot.com/2010/08/adding-support-for-enum-properties-on.html">Davy Landman</a>.</p>
<p>Eine andere Möglichkeit ist die Verwendung des &#8220;Parse&#8221; und des &#8220;Format&#8221; Events der Datenbindung. Da ich einige ComboBoxen habe und die Events nicht jedesmal komplett neu registrieren möchte, hab ich mir ne kleine Helperklasse geschrieben:</p>
<pre class="brush: csharp">public static class EnumHelper
{
    public static void BindToComboBox(ComboBox comboBox, string propertyName)
    {
        if (typeof(E).IsEnum)
        {
            comboBox.DataBindings[propertyName].Format += (sender, e) =&gt; { e.Value = (E)e.Value; };
            comboBox.DataBindings[propertyName].Parse += (sender, e) =&gt; { e.Value = (int)e.Value; };

            comboBox.DataSource = Enum.GetValues(typeof(E));
        }
    }
}</pre>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=232&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2011/02/windows-forms-entity-framework-datenbindung-enums-und-comboboxen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows Forms: Nullable ComboBox</title>
		<link>http://www.nw-software.com/2011/02/windows-forms-nullable-combobox/</link>
		<comments>http://www.nw-software.com/2011/02/windows-forms-nullable-combobox/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 14:10:40 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=222</guid>
		<description><![CDATA[Auf der Suche nach einer Möglichkeit, einer ComboBox zusätzlich zu den eigentlichen Werten auch einen Eintrag für einen Nullwert zu spendieren habe ich schlussendlich folgende Umsetzung gewählt, die bisher ganz gut funktioniert. Wenn jemand Schwachstellen findet darf er sich gerne in den Kommentaren auslassen: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using [...]]]></description>
			<content:encoded><![CDATA[<p>Auf der Suche nach einer Möglichkeit, einer ComboBox zusätzlich zu den eigentlichen Werten auch einen Eintrag für einen Nullwert zu spendieren habe ich schlussendlich folgende Umsetzung gewählt, die bisher ganz gut funktioniert. Wenn jemand Schwachstellen findet darf er sich gerne in den Kommentaren auslassen:</p>
<pre class="brush: csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;

namespace com.boobe.salesman.ui.Controls
{
    public class NullableComboBox : ComboBox
    {
        public string NullLabel { get; set; }
        public object NullValue { get; set; }

        private string _displayMember;
        public new string DisplayMember
        {
            get { return _displayMember; }
            set { _displayMember = value; }
        }

        public NullableComboBox()
        {
            NullLabel = "";
            NullValue = null;

            base.ValueMember = "Entity";
            base.DisplayMember = "Title";
        }

        private object _dataSource;
        private IList _items;
        new public object DataSource
        {
            get { return _dataSource; }
            set
            {
                if (value.GetType().IsAssignableFrom(typeof(IEnumerable)))
                    throw new ArgumentException("Nur von IEnumerable abgeleitete Typen sind erlaubt.");

                if (_dataSource != null &amp;&amp; _dataSource == value)
                    return;

                _dataSource = value;

                IEnumerable&lt;object&gt; list = (IEnumerable&lt;object&gt;)value;

                _items = new List();
                foreach (object current in list)
                {
                    PropertyInfo propertyInfo = current.GetType().GetProperty(DisplayMember);
                    string title = propertyInfo != null ? propertyInfo.GetValue(current, null).ToString() : current.ToString();
                    _items.Add(new NullableComboBoxItem { Title = title, Entity = current });
                }
                _items.Insert(0, new NullableComboBoxItem { Title = NullLabel, Entity = NullValue });

                base.DataSource = _items;
            }
        }

        new public object SelectedItem
        {
            get
            {
                NullableComboBoxItem selectedItem = (NullableComboBoxItem)base.SelectedItem;
                return selectedItem == null ? null : selectedItem.Entity;
            }
            set
            {
                foreach (NullableComboBoxItem cur in _items)
                {
                    if (cur.Entity == value)
                        base.SelectedItem = cur;
                }
            }
        }

        private class NullableComboBoxItem
        {
            public string Title { get; set; }
            public object Entity { get; set; }
        }
    }
}</pre>
<p>Verwendet wird die ComboBox wie folgt:</p>
<pre class="brush: csharp">colorComboBox.NullLabel = "";
colorComboBox.NullValue = null;
colorComboBox.DisplayMember = "ColorName";
colorComboBox.DataSource = context.ProductColors.Where(x =&gt; x.Discontinued == false);</pre>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=222&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2011/02/windows-forms-nullable-combobox/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unit Tests von EJBs (mit JPA) mittels Embedded Glassfish v3 in NetBeans 6.8 und Maven</title>
		<link>http://www.nw-software.com/2010/02/unit-tests-von-ejbs-mit-jpa-mittels-embedded-glassfish-v3-in-netbeans-6-8-und-maven/</link>
		<comments>http://www.nw-software.com/2010/02/unit-tests-von-ejbs-mit-jpa-mittels-embedded-glassfish-v3-in-netbeans-6-8-und-maven/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 18:38:31 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=192</guid>
		<description><![CDATA[Unit Tests sind in Java EE Anwendungen nicht so einfach zu realisieren, da die EJBs im EJB Container ablaufen. Daher gibt es seit 3.1 so genannte Embedded EJB Container. Darüber gibt es auch wieder einige tolle Blog Einträge, doch leider hat mich keiner der vorhanden direkt zum Erfolg geführt, deshalb hier mal meine Anleitung. Wie [...]]]></description>
			<content:encoded><![CDATA[<p>Unit Tests sind in Java EE Anwendungen nicht so einfach zu realisieren, da die EJBs im EJB Container ablaufen. Daher gibt es seit 3.1 so genannte Embedded EJB Container. Darüber gibt es auch wieder einige tolle Blog Einträge, doch leider hat mich keiner der vorhanden direkt zum Erfolg geführt, deshalb hier mal meine Anleitung.</p>
<p>Wie der Titel schon sagt verwende ich NetBeans 6.8 mit Glassfish v3 und Maven für meine Java EE 6 Anwendung. Wie es sich gehört wird fleißig Einsatz von JPA gemacht. Hier wird  mal vorausgesetzt, dass die Anwendung schon brav Kontakt zur Datenbank aufgenommen hat, in meinem Fall MySQL, sprich alle JDBC Pools und Connections wurden erfolgreich angelegt. Somit können wir später direkt die Konfiguration der Domains des richtigen Glassfish Application Servers in unserem Embedded Container verwenden um mittels JPA auf die Datenbank zu zu greifen. Wer lieber zum Testen eine seperate Datenbank nehmen möchte kann <a href="http://ctpjava.blogspot.com/2009/10/unit-testing-ejbs-and-jpa-with.html">hier</a> nachlesen wie er da vorgehen muss.</p>
<p>Als erstes muss die embedded Version des Glassfishes in Maven eingebunden werden. Hier ergab sich bereits mein erstes Problem, da sich die Repositories und der notwendige Dependency Eintrag nicht so einfach im Internet finden lassen. Deshalb hier die Abhängigkeit:</p>
<pre class="brush: xml">&lt;dependency&gt;
  &lt;groupId&gt;org.glassfish.extras&lt;/groupId&gt;
  &lt;artifactId&gt;glassfish-embedded-all&lt;/artifactId&gt;
  &lt;version&gt;3.0&lt;/version&gt;
  &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</pre>
<pre class="brush: xml">&lt;dependency&gt;
  &lt;groupId&gt;javax&lt;/groupId&gt;
  &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;
  &lt;version&gt;6.0&lt;/version&gt;
  &lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;</pre>
<p>Der untere Eintrag wird für den Container zwar nicht benötigt, wird hier aber dennoch erwähnt, da es wichtig ist, das der embedded Glassfish Eintrag vor diesem in der pom.xml erscheint, da es sonst zu Fehlermeldungen beim Testen und Deployen kommen kann.<br />
Der zugehörige Repository Eintrag lautet wie folgt:</p>
<pre class="brush: xml">&lt;repository&gt;
  &lt;id&gt;embedded-glassfish&lt;/id&gt;
  &lt;name&gt;Embedded Glassfish Maven Repository&lt;/name&gt;
  &lt;url&gt;http://download.java.net/maven/glassfish&lt;/url&gt;
&lt;/repository&gt;</pre>
<p>Nun sollten diese Abhängigkeiten erstmal durch ein Build besorgt werden um zu sehen ob hier alles geklappt hat. Achtung! die embedded Version des Glassfish hat knapp 45MB, das Herunterladen kann also etwas dauern (wenn man wie ich nur ne 768kBit/s Leitung hat).</p>
<p>Nun kümmern wir uns um die Unit Tests. Dazu poste ich euch hier einen komplett funktionsfähigen Test den ich im Anschluss versuche zu erläutern. Da ich nämlich keinen kompletten Test in anderen Blogs finden konnte, sondern nur Codeschnipsel, hatte ich am Anfang noch mit einigen Exceptions zu kämpfen (naja, ich programmiere erst seit ein paar Wochen in Java, was will man erwarten).</p>
<pre class="brush: java">package sample.test.controller;

import sample.controller.UserEntityFacade;
import sample.model.UserEntity;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.ejb.embeddable.EJBContainer;
import javax.naming.Context;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.Assert;

public class UserEntityFacadeFixture {

    public UserEntityFacadeFixture() {
    }

    public static EJBContainer container;
    public static Context context;
    public static UserEntityFacade facade;

    @BeforeClass
    public static void setUpClass() throws Exception {
        Map properties = new HashMap();
        properties.put(EJBContainer.MODULES, new File("target/classes"));
        properties.put("org.glassfish.ejb.embedded.glassfish.installation.root", "/Applications/NetBeans/sges-v3/glassfish");
        container = EJBContainer.createEJBContainer(properties);
        context = container.getContext();
        facade = (UserEntityFacade)context.lookup("java:global/classes/UserEntityFacade");
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
        context.close();
        container.close();
    }

    @Before
    public void setUp() {
    }

    @After
    public void tearDown() {
    }

    @Test
    public void CreateUserEntity() {
        UserEntity user = new UserEntity();
        user.setUsername("jack");
        user.setPassword("jack");

        int count = facade.count();
        facade.create(user);
        Assert.assertEquals(count + 1, facade.count());
    }
}</pre>
<p>Hauptaugenmerk muss hier natürlich auf die Initialisierung des Containers gelegt werden. Dazu werden statische Variablen angelegt um den Container beim Start des Tests zu Starten und für alle Tests zur Verfügung zu haben. Am Ende der Tests wird der Container und der Context wieder geschlossen. Man beachte auch den import Bereich, da ich bei simpler Angabe von &#8220;public static Context context;&#8221; in einigen Codeschnipseln nämlich nicht rauslesen konnte das es sich dabei um den &#8220;javax.naming.Context&#8221; handeln soll. Aber wahrscheinlich ist das allen Java Experten klar.</p>
<p>Beim Erstellen des Containers wird der <em>createEJBContainer</em> Mehtode hier eine Hashmap mit Einstellungen übergeben. Dies ist an dieser Stelle wichtig, da wir JPA verwenden und daher das Verzeichnis vom Glassfish mit angeben müssen, damit der EJB Container die Konfiguration der JDBC Resourcen aus dessen Konfiguration lesen kann. Wird kein JPA verwendet, können die Einstellungen ganz entfallen, sprich es wird kein Parameter übergeben.</p>
<p>Anschließend holt man sich den Context und frägt daraus seine EJBs an. An dieser Stelle hatte ich auch wieder zu kämpfen. Mir war nicht ganz klar wie sich der JNDI Name aufbaut. Beim JBOSS hätte ich jetzt immerhin gewusst wo ich diesen nachschauen kann. Bei TheServerSide werden <a href="http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesinEJB31-Part5">die mit EJB 3.1 eingeführten globalen JNDI Namen</a> zwar erläutert, doch damit ließen sich meine Beans dennoch nicht auffinden. Nach langem Suchen bin ich dann auf die einfache und funktionierende Version oben gestoßen. Dabei ist der vordere Teil fest und nur der Name der Bean angehängt. Wenn mir jemand diesen Sachverhalt genauer erklären kann darf er sich in den Kommentaren dazu gerne auslassen ;-)</p>
<p>Der Rest des Listings dürfte hoffentlich keine Schwierigkeiten bereiten. Der Vollständigkeit halber hier noch die Blog Posts, die mir hierbei sehr hilfreich waren:</p>
<p>[1] <a href="http://blogs.sun.com/alexismp/entry/testing_ejb_3_1_s">Using the EJBContainer API with or without Maven (but with GlassFish v3)</a><br />
[2] <a href="http://ctpjava.blogspot.com/2009/10/unit-testing-ejbs-and-jpa-with.html"><span style="font-weight: normal;">Unit Testing EJBs and JPA with Embeddable GlassFish</span></a><br />
[3] <a href="http://www.adam-bien.com/roller/abien/entry/embedding_ejb_3_1_container">EMBEDDING EJB 3.1 CONTAINER INTO YOUR UNIT TESTS &#8211; BOOT TIME: 5 SECONDS</a><br />
[4] <a href="http://www.adam-bien.com/roller/abien/entry/how_to_unit_test_ejb">HOW TO UNIT-TEST EJB 3 &#8230;IN 0.8 SECONDS [SOURCE CODE INCLUDED]</a><br />
[5] <a href="http://javahowto.blogspot.com/2009/12/ejb-lite-testing-with-junit-and.html">EJB Lite testing with JUnit and embeddable container</a></p>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=192&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2010/02/unit-tests-von-ejbs-mit-jpa-mittels-embedded-glassfish-v3-in-netbeans-6-8-und-maven/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Java CLASSPATH unter Mac OS X: Wie verheirate ich MySQL und Glassfish</title>
		<link>http://www.nw-software.com/2010/02/java-classpath-unter-mac-os-x/</link>
		<comments>http://www.nw-software.com/2010/02/java-classpath-unter-mac-os-x/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 15:54:29 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=179</guid>
		<description><![CDATA[Bei meinen ersten Schritten mit Java auf dem Mac zu programmieren bin ich gleich mal derbe auf die Fresse gefallen. Gut, es war vielleicht auch nicht die beste Idee gleich mit einer Maven Enterprise Application anzufangen, aber hey, wer nichts wagt der nicht gewinnt. Größtes Problem hierbei war MySQL und Glassfish v3 zur Zusammenarbeit zu [...]]]></description>
			<content:encoded><![CDATA[<p>Bei meinen ersten Schritten mit Java auf dem Mac zu programmieren bin ich gleich mal derbe auf die Fresse gefallen. Gut, es war vielleicht auch nicht die beste Idee gleich mit einer Maven Enterprise Application anzufangen, aber hey, wer nichts wagt der nicht gewinnt. Größtes Problem hierbei war MySQL und Glassfish v3 zur Zusammenarbeit zu bewegen. Alle Tutorials reden immer davon eine Datenbankverbindung in NetBeans anzulegen, die Tabellen zu erstellen und eine Persistence Unit für MySQL dem Projekt hinzuzufügen. Bis dahin auch toll und sicherlich nicht falsch, nur bringt das alles nichts wenn man zuvor nicht MySQL und Glassfish verheiratet was soviel heißt wie einen MySQL Connection Pool in der Glassfish Adminconsole anzulegen. Für alle Idioten da draußen die, wie ich ;-), nicht wissen wie man da hin kommt, einfach im Browser http://localhost:4848 eingeben während Glassfish läuft. Eine gute Anleitung zur Hochzeit findet man <a href="http://gardiary.wordpress.com/2009/07/30/create-jdbc-connection-pool-and-resource-in-glassfish/">hier</a> und <a href="http://www.innoq.com/blog/gs/2007/10/howto_get_jsasglassfish_with_m.html">hier</a>.</p>
<p>Doch das eigentliche Problem trat bei mir ganz am Anfang der Anleitung auf. Man muss den MySQL Connector für Java im CLASSPATH hinterlegen. Nun reicht es dabei unter Windows schon aus den Connector im Glassfish Verzeichnis in lib zu positionieren, was auf dem Mac unseren geliebten Application Server aber noch lange nicht zufrieden stellt. Nach langem Stöbern bei Onkel Google bin ich über den Beitrag <a href="http://book.javanb.com/mac-os-x-for-java-geeks/0596004001_macxjvgks-chp-2-sect-2.html">Mac OS X for Java Geeks</a> gestolpert, der mir die CLASSPATH Geschichte des Betriebssystems näher zu bringen versuchte. Allerdings hat auch das Ablegen der Connector JAR Datei im Extension Ordner des Java Verzeichnisses nur wenig Erfolg gezeigt.</p>
<p>Erst in einem Forum Post hab ich die für mich funktionierende Lösung tatsächlich gefunden. Innerhalb von NetBeans kann man die CLASSPATH Variablen verwalten. Dazu geht man im Menü auf &#8220;Tools&#8221; und anschließend auf &#8220;Libraries&#8221;. Links findet man eine Liste die in Class- und Server Libraries aufgeteilt ist. Unter Server ist schließlich ein Eintrag &#8220;Java-EE-GlassFish-v3&#8243;. Nach anwählen kann man sich im Fenster rechts die enthaltenen Bibliotheken ansehen. Nach kurzem durchforsten fällt auf das diese alle unter &#8220;/Applications/NetBeans/sges-v3/glassfish/modules/&#8221; liegen. Also habe ich kurzerhand den MySQL Connector da rein geschmissen und hier als Library mittels &#8220;Add JAR/Folder&#8230;&#8221; hinzugefügt. Im Anschluss noch kurz Glassfish neugestartet und schon funktioniert der Ping auf den MySQL Connection Pool wie gewünscht. Nun kann mit den oben genannten Tutorials weiter verfahren werden um MySQL zum Connection Pool hinzu zu fügen.</p>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=179&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2010/02/java-classpath-unter-mac-os-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Probleme beim Veröffentlichen von ASP.Net kompatibler WCF Services</title>
		<link>http://www.nw-software.com/2010/01/probleme-beim-veroffentlichen-von-asp-net-kompatibler-wcf-services/</link>
		<comments>http://www.nw-software.com/2010/01/probleme-beim-veroffentlichen-von-asp-net-kompatibler-wcf-services/#comments</comments>
		<pubDate>Wed, 27 Jan 2010 16:41:19 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[WCF]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=161</guid>
		<description><![CDATA[Wer, wie ich gerade, Probleme beim Veröffentlichen von WCF Services in einer ASP.Net Webseite hat sollte sich mal folgende zwei Artikel zu Gemüte führen: http://social.msdn.microsoft.com/forums/en-US/wcf/thread/8c897f8e-2143-450e-a9f4-97d1f8702da7/ http://nimtug.org/blogs/damien-mcgivern/archive/2008/01/30/wcf-required-precompiled-asp-net-site-to-be-updatable.aspx Der charmante und gleichzeitig nichts aussagende Fehler &#8220;Der Wert darf nicht NULL sein. Parametername: key&#8221; hat mich fast in den Wahnsinn getrieben. Gleichzeitig ist es in einer deutschen Entwicklungsumgebung [...]]]></description>
			<content:encoded><![CDATA[<p>Wer, wie ich gerade, Probleme beim Veröffentlichen von WCF Services in einer ASP.Net Webseite hat sollte sich mal folgende zwei Artikel zu Gemüte führen:</p>
<p><a href="http://social.msdn.microsoft.com/forums/en-US/wcf/thread/8c897f8e-2143-450e-a9f4-97d1f8702da7/">http://social.msdn.microsoft.com/forums/en-US/wcf/thread/8c897f8e-2143-450e-a9f4-97d1f8702da7/</a></p>
<p><a href="http://nimtug.org/blogs/damien-mcgivern/archive/2008/01/30/wcf-required-precompiled-asp-net-site-to-be-updatable.aspx">http://nimtug.org/blogs/damien-mcgivern/archive/2008/01/30/wcf-required-precompiled-asp-net-site-to-be-updatable.aspx</a></p>
<p>Der charmante und gleichzeitig nichts aussagende Fehler &#8220;Der Wert darf nicht NULL sein. Parametername: key&#8221; hat mich fast in den Wahnsinn getrieben. Gleichzeitig ist es in einer deutschen Entwicklungsumgebung gar nicht mal so einfach auf die richtige Lösung im Internet zu stoßen wenn man erstmal die Fehlermeldung richtig übersetzen muss ;-)</p>
<p>Meine Umgebung läuft auf Windows XP. Entwickelt wird mit Visual Studio 2008 und dem .Net Framework 3.5 SP1. Als IIS kommt die 5.1 Version die bei XP mitgeliefert wurde zum Einsatz. Nur um das mal erwähnt zu haben.</p>
<p>Einfach beim Veröffentlichen den Haken bei &#8220;Aktualisierbarkeit dieser vorkompilierten Site zulassen&#8221; (zumindest im deutschen Visual Studio) und schon laufen die Webservices ohne Fehlermeldung. Ob sich diese Variante für Anwendungen eignet, die ausgeliefert werden sollen, sei mal dahin gestellt. Für Intranetanwendungen aber ein interessanter Workaround.</p>
<p>Der andere Ansatz ist das Bearbeiten der .compiled Dateien die sich in der Webanwendung im bin Verzeichnis befinden sollten. In meinem Fall lautet der Name der Website in Visual Studio &#8220;Website&#8221;. Daher werden alle Service Dateien so kompiliert das sie auf &#8220;Website\Servicename.svc&#8221; verweisen. In den .compiled Dateien sieht das in etwa so aus:</p>
<pre class="brush: xml">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;preserve resultType="5" virtualPath="/Website/ContentService.svc" [...] customString="/Website/ContentService.svc||ContentService|App_Web_c4jmapxp, [...]"&gt;
&lt;filedeps&gt;
&lt;filedep name="/Website/ContentService.svc" /&gt;
&lt;/filedeps&gt;
&lt;/preserve&gt;</pre>
<p>Anstatt &#8220;Website&#8221; sollte man hier nun den Namen des virtuellen Verzeichnisses, das man im IIS verwendet, wählen. Einfach wird es aber wenn man diesen einfach durch eine Tilde ~ ersetzt:</p>
<pre class="brush: xml">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;preserve resultType="5" virtualPath="~/ContentService.svc" [...] customString="~/ContentService.svc||ContentService|App_Web_c4jmapxp, [...]"&gt;
&lt;filedeps&gt;
&lt;filedep name="~/ContentService.svc" /&gt;
&lt;/filedeps&gt;
&lt;/preserve&gt;</pre>
<p>Und schon funktioniert die Seite mit WCF Services auch ohne Updatefähigkeit in anderen IIS Umgebungen. Allerdings muss diese Ersetzung jedes mal von Hand in allen .compiled Dateien durchgeführt werden.</p>
<p><strong>Update</strong></p>
<p>Mein Script zum Suchen und Ersetzen ist fertig. Es besteht aus zwei Dateien. Zuerst die LoopThroughCompiledFiles.bat:</p>
<pre class="brush: bash">for /f %%a IN ('dir /b *.compiled') do call :Replace "%%a"
exit /b

:Replace
cscript //nologo ..\..\replace.vbs /Website ~ %~1
exit /b</pre>
<p>Dieses Script macht folgendes: die for-Schleife geht durch den Schalter /f alle Dateien der folgenden dir Abfrage durch. Diese wiederum liefert nur Dateien mit der Endung .compiled. Der Schalter /b sorgt dafür das nur die Dateinamen mit Erweiterungen durchlaufen werden. Anschließend wird mit jedem Dateinamen der Replace Teil aufgerufen. Hier wird ein VB Script zum Suchen und Ersetzen aufgerufen. Wobei die Strings hier mit &#8220;/Website&#8221; und &#8220;~&#8221; hartcodiert sind. Mein Dank an dieser Stelle gilt James Welch für seinen hervorragenden Blog Eintrag &#8220;<a href="http://jamesewelch.wordpress.com/2008/05/01/how-to-write-a-dos-batch-file-to-loop-through-files/">How to write a DOS batch file to loop through files</a>&#8220;.</p>
<p>Nun hier natürlich auch noch der Code des VB Scripts replace.vbs, den ich von ghostmachine4 aus <a href="http://www.dostips.com/forum/viewtopic.php?p=2600&amp;highlight=#2600">diesem Forumpost</a> übernommen und angepasst habe (Danke auch dafür):</p>
<pre class="brush: vb">strOld = WScript.Arguments.Item(0)
strNew = WScript.Arguments.Item(1)
strF1 = WScript.Arguments.Item(2)
strF2 = strF1 &amp; ".replaced"
Const ForWriting = 2

Set fso=CreateObject("Scripting.FileSystemObject")

Set f1 = fso.OpenTextFile(strF1)
Set f2 = fso.OpenTextFile(strF2, ForWriting, True)

Do Until f1.AtEndOfStream
   strLine = f1.ReadLine
   f2.WriteLine(Replace(strLine,strOld,strNew))
Loop

f1.Close
f2.Close

Set f1 = fso.GetFile(strF1)
f1.Delete()

Set f2 = fso.GetFile(strF2)
f2.Move(strF1)</pre>
<p>Hier werden zuerst die Übergabeparameter ausgelesen und die entsprechenden Dateien angelegt und geöffnet. Dabei wird in eine temporäre Datei geschrieben. Die Originaldatei wird im Anschluss gelöscht und die temporäre Datei mit deren Dateiname versehen.</p>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=161&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2010/01/probleme-beim-veroffentlichen-von-asp-net-kompatibler-wcf-services/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WiX IIsExtension: Deutsche Lokalisierungsdatei</title>
		<link>http://www.nw-software.com/2009/10/wix-iisextension-deutsche-lokalisierungsdatei/</link>
		<comments>http://www.nw-software.com/2009/10/wix-iisextension-deutsche-lokalisierungsdatei/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 09:18:44 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[Software Entwicklung]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=142</guid>
		<description><![CDATA[Momentan versuche ich gerade einen lokalisierbaren WiX Installer für eines meine Webprojekte zu erstellen. Ansich ist WiX da eine feine Sache, nur mit der Lokalisierung habe ich meine Problem. Vor allem, da beim Verwenden der IIS Extension für WiX nur die Sprache en-US möglich ist, da nur diese in der Library verfügbar ist. Wird wie [...]]]></description>
			<content:encoded><![CDATA[<p>Momentan versuche ich gerade einen lokalisierbaren <a href="http://wix.sourceforge.net/">WiX</a> Installer für eines meine Webprojekte zu erstellen. Ansich ist WiX da eine feine Sache, nur mit der Lokalisierung habe ich meine Problem. Vor allem, da beim Verwenden der IIS Extension für WiX nur die Sprache en-US möglich ist, da nur diese in der Library verfügbar ist. Wird wie bei mir die Sprache auf de-DE gestellt, bekommt man einige unschöne Fehlermeldungen beim kompilieren des Projekts:</p>
<p><code>C:\delivery\Dev\wix35_public\src\ext\IIsExtension\wixlib\IIsExtension.wxs(65,0): error LGHT0102: The localization variable !(loc.ConfigureIIs) is unknown.  Please ensure the variable is defined.</code></p>
<p>Um nur einen zu nennen. Um dieses Problem zu umgehen müssen nur die entsprechenden Lokalisierungsvariablen in das eigene Lokalisierungsfile übernommen werden. Damit nicht jeder selber übersetzen muss biete ich euch hier meine Übersetzung an: <a href="http://www.nw-software.com/wp-content/uploads/2009/10/de-de.wxl">WiX IIsExtension Lokalisierungsdatei de-DE</a></p>
<p>Diese Datei entweder in das Verzeichnis /src/ext/IIsExtension/wixlib der WiX Sourcen kopieren und diese neu kompilieren oder die Variablen rauskopieren und in einer eigenen Lokalisierungsdatei hinterlegen und manuell beim Kompilieren und Linken mit WiX angeben.</p>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=142&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2009/10/wix-iisextension-deutsche-lokalisierungsdatei/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Threadsichere Events in C#</title>
		<link>http://www.nw-software.com/2009/09/threadsichere-events-in-c/</link>
		<comments>http://www.nw-software.com/2009/09/threadsichere-events-in-c/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 09:19:57 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[Software Entwicklung]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=77</guid>
		<description><![CDATA[In einem Projekt ergab sich die Problemstellung das eine Resource die in einem Thread geladen wird, andere Programmteile über eine erfolgreiche Aktualisierung informiert. Dabei musste natürlich großes Augenmerk auf die Threadsicherheit gelegt werden. Daher musste zunächst eine Lösung her um Events Threadsicher zu feuern. Nach kurzem Suchen bin ich auf den Artikel im GMBSG Blog [...]]]></description>
			<content:encoded><![CDATA[<p>In einem Projekt ergab sich die Problemstellung das eine Resource die in einem Thread geladen wird, andere Programmteile über eine erfolgreiche Aktualisierung informiert. Dabei musste natürlich großes Augenmerk auf die Threadsicherheit gelegt werden. Daher musste zunächst eine Lösung her um Events Threadsicher zu feuern. Nach kurzem Suchen bin ich auf den <a href="http://www.gmbsg.com/works/index.php?title=Events_threadsicher_aufrufen_in_.NET">Artikel</a> im <a href="http://www.gmbsg.com/works/index.php?title=Digitale_Manufaktur">GMBSG Blog</a> aufmerksam geworden. Hier wird eine statische Klasse zum threadsicheren auslösen eines Events gezeigt, die zudem noch versucht das Event im Kontext des jeweiligen Threads der das Event empfangen möchte ablaufen zu lassen:</p>
<pre class="brush: csharp">public static class ThreadSafeInvoker
{
 public static void Invoke(Delegate method, object[] args)
 {
  if (method != null)
  {
   foreach (Delegate handler in method.GetInvocationList())
   {
    if (handler.Target is Control)
    {
     Control target = handler.Target as Control;

     if (target.IsHandleCreated)
     {
      target.BeginInvoke(handler, args);
     }
    }
    else if (handler.Target is ISynchronizeInvoke)
    {
     ISynchronizeInvoke target = handler.Target as ISynchronizeInvoke;
     target.BeginInvoke(handler, args);
    }
    else
    {
     handler.DynamicInvoke(args);
    }
   }
  }
 }
}</pre>
<p>Natürlich sind dabei Anpassungen beim Empfänger notwendig. Entweder man leitet seine Klasse von Control ab oder man  erstellt eine eigene Implementierung von ISynchronizeInvoke. Da diese Implementierung aber wohl nicht so einfach von statten geht, gehen viele dazu über einfach von Control abzuleiten auch wenn ihre Klasse nichts mit einem Steuerelement zu tun haben. <a href="http://www.idesign.net/idesign/desktopdefault.aspx">IDesign</a> bietet <a href="http://www.idesign.net/idesign/uploads/Synchronizer.zip">hier</a> eine Beispielhafte Implementierung für ISynchronizeInvoke an. Da in meinem Projekt das aktualisieren der Resource ohnehin automatisch im Mainthread statt findet, war keine spezielle Implementierung notwendig.</p>
<p>Weiter ist es aber noch wichtig das An- und Abmelden zu bzw. von einem Event threadsicher zu machen.</p>
<pre class="brush: csharp">private CacheItemChangedEventHandler changedEvent;
readonly object changedEventLock = new object();

public event CacheItemChangedEventHandler Changed
{
 add
 {
  lock (changedEventLock)
  {
   changedEvent += value;
  }
 }
 remove
 {
  lock (changedEventLock)
  {
   changedEvent -= value;
  }
 }
}</pre>
<p>Weiter muss beim Auslösen des Events ebenfalls gelockt werden. Da es aber hierdurch ebenfalls zu Deadlocks kommen kann werden die Eventlistener nur im Lockbereich kopiert und anschließend außerhalb des Locks mit der oben erwähnten statischen Klasse informiert:</p>
<pre class="brush: csharp">private void OnChanged()
{
 CacheItemChangedEventHandler copy;

 lock (changedEventLock)
 {
  copy = changedEvent;
 }

 if (copy != null)
 {
  foreach (Delegate cur in copy.GetInvocationList())
  {
   ThreadSafeInvoker.Invoke(cur, new object[] { this, new CacheItemChangedEventArgs(this) });
  }
 }
}</pre>
<p>Weiter gab es bei dem Projekt das Problem das es nicht möglich war festzustellen ob sich ein Listener der über das Event informiert werden will bereits bei der Resource registriert hat oder nicht. Eine Möglichkeit wäre gewesen, jedes Resourcenobjekt in eine Liste zu schmeißen und beim registrieren zum Event vorher zu testen ob für die Resource bereits ein Eintrag in der Liste vorhanden ist und wenn ja muss keine erneute Registrierung erfolgen. Da diese Praktik mir als unschön erschien und sich jede Klasse merken müsste ob sie sich schon registriert hat, wurde die add Methode des Events etwas erweitert:</p>
<pre class="brush: csharp">public event CacheItemChangedEventHandler Changed
{
 add
 {
  lock (changedEventLock)
  {
   if (changedEvent != null)
    foreach (Delegate cur in changedEvent.GetInvocationList())
     if (cur.Target == value.Target)
      return;

   changedEvent += value;
  }
 }
 ...
}</pre>
<p>So wird ein neuer Listener nur noch hinzugefügt wenn er nicht schon vorhanden ist.</p>
<p>Für Kritik und Anregungen wäre ich euch sehr dankbar.</p>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=77&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2009/09/threadsichere-events-in-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fehler bei Aufruf in Managed C++ Assembly von C# aus nach Visual Studio 2005 Update (KB971090)</title>
		<link>http://www.nw-software.com/2009/08/fehler-bei-aufruf-in-managed-c-assembly-von-c-aus-nach-visual-studio-2005-update-kb971090/</link>
		<comments>http://www.nw-software.com/2009/08/fehler-bei-aufruf-in-managed-c-assembly-von-c-aus-nach-visual-studio-2005-update-kb971090/#comments</comments>
		<pubDate>Tue, 25 Aug 2009 12:34:07 +0000</pubDate>
		<dc:creator>Niko Will</dc:creator>
				<category><![CDATA[Software Entwicklung]]></category>

		<guid isPermaLink="false">http://www.nw-software.com/?p=75</guid>
		<description><![CDATA[Neulich hat mein Entwicklungsrechner bei der Arbeit mal wieder munter Updates gezogen und unter anderem auch das oben angesprochene. Folge war, das ein .NET Projekt von uns das mittels einer managed C++ Assembly auf DirectX zugegriffen hat, einen Fehler auf Nichtentwicklungsmaschinen produzierte. Vor allem die Fehlermeldung selber war super schlüssig und sagte irgendwas von &#8220;Anwendungskonfigurationsdatei [...]]]></description>
			<content:encoded><![CDATA[<p>Neulich hat mein Entwicklungsrechner bei der Arbeit mal wieder munter Updates gezogen und unter anderem auch das oben angesprochene. Folge war, das ein .NET Projekt von uns das mittels einer managed C++ Assembly auf DirectX zugegriffen hat, einen Fehler auf Nichtentwicklungsmaschinen produzierte. Vor allem die Fehlermeldung selber war super schlüssig und sagte irgendwas von &#8220;Anwendungskonfigurationsdatei der Assembly blablablub nicht gefunden&#8221;. Nun konnte diese Konfig Datei auch nicht gefunden werden, da es noch nie eine gab. Nach mehreren Stunden stöbern im Netz bin ich dann mehr oder weniger auf die Lösung gestoßen. Und zwar wird durch das Update die vcredist_x86.exe im Verzeichnis C:\Programme\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\vcredist_x86\ aktualisiert und muss deshalb auf dem Zielcomputer ebenfalls neu ausgeführt werden.</p>
<p>Wer lieber mit der alten VC++ Version weiter arbeiten möchte, findet auf Teds Blog eine <a href="http://tedwvc.wordpress.com/2009/08/10/avoiding-problems-with-vc2005-sp1-security-update-kb971090/">Lösung</a> dafür.</p>
<img src="http://www.nw-software.com/?ak_action=api_record_view&id=75&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.nw-software.com/2009/08/fehler-bei-aufruf-in-managed-c-assembly-von-c-aus-nach-visual-studio-2005-update-kb971090/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

