<?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>GhoUl &#187; java</title>
	<atom:link href="http://cubussapiens.hu/tag/java/feed/" rel="self" type="application/rss+xml" />
	<link>http://cubussapiens.hu</link>
	<description>A Cubus Sapiens oldal</description>
	<lastBuildDate>Fri, 24 Feb 2012 21:53:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Reusing PDE in modeling context</title>
		<link>http://cubussapiens.hu/2011/11/reusing-pde-in-modeling-context/</link>
		<comments>http://cubussapiens.hu/2011/11/reusing-pde-in-modeling-context/#comments</comments>
		<pubDate>Wed, 09 Nov 2011 12:49:36 +0000</pubDate>
		<dc:creator>Balage</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[emf]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[PDE]]></category>
		<category><![CDATA[Xtext]]></category>

		<guid isPermaLink="false">http://cubussapiens.hu/?p=2187</guid>
		<description><![CDATA[If you&#8217;re developing with EMF it is a common task to separate the model into multiple files along with enabling the user to create crosslinks between them. This works out-of box if the files are located inside the same project. &#8230; <a href="http://cubussapiens.hu/2011/11/reusing-pde-in-modeling-context/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re developing with EMF it is a common task to separate the model into multiple files along with enabling the user to create crosslinks between them. This works out-of box if the files are located inside the same project. However, in some cases for larger models it is simply not enough. It can be useful to be able to define reusable (and versioned) packets of models and enable the user to define a configuration which determines the imported model packages. Sounds familiar? The same functionality exists in PDE. Maybe it can be reused for non-java purposes.</p>
<p><span id="more-2187"></span></p>
<p><strong>Plug-ins as model containers</strong></p>
<p>Creating plug-in projects to contain models is easy with PDE: not even a single line of code is needed. The user can create a non-java plug-in project, or convert a resource project to plug-in project by clicking on &#8216;Configure/Convert to Plug-in projects&#8217; in the pop-up menu of the project.</p>
<p>It&#8217;s finished: the user now can define dependencies between projects and even install/update third party plug-ins from update sites!</p>
<p><strong>Creating cross-links</strong></p>
<p>Of course, if the user wants to use the models from the dependent plug-ins we must show the contents of these models on the GUI. This step is highly domain-specific, therefore I leave it to the reader. The part of determining the visible resources from the imported plug-ins is common for all uses.</p>
<p>To use the dependent models, we need to load not only the directly referenced plug-ins, but the plug-ins needed by them recursively:</p>
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false">/**
 * Collect all plug-ins on which the given plug-in depends.
 * @param name
 * @return
 */
public static List&lt;String&gt; collectAllDependencies(String name){
    Set&lt;String&gt; all = new HashSet&lt;String&gt;();

    Queue&gt;IPlugin&lt; process = new LinkedList&lt;IPlugin&gt;();
    process.add(getPlugin(name));

    while(!process.isEmpty()){
        IPlugin plugin = process.poll();
        all.add(plugin.getId());
        for(IPluginImport pi : plugin.getImports()){
            String imported = pi.getId();
            if (!all.contains(imported)){
                process.add(getPlugin(imported));
            }
        }
    }

    return new ArrayList&lt;String&gt;(all);
}

public static IPlugin getPlugin(String name){
    IPluginModelBase mb = PluginRegistry.findModel(name);
    IPluginModel m = (IPluginModel)mb;
    return m.getPlugin();
}</pre>
<p>When we got all plug-ins to use, we just need to collect the resources from them. In this step we must prepare for two cases: whether the plug-in is a workspace plug-in or not. A workspace plug-in is a plug-in in development. There is a project in the workspace which contain the plug-in contents. Unlike installed plug-ins which exists in the plugins directory of the eclipse installation:</p>
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false">public static Collection&lt;URI&gt; getVisibleResources(String pluginname) throws CoreException{
    IPlugin plugin = getPlugin(pluginname);
    final Collection&lt;URI&gt; result = new ArrayList&lt;URI&gt;();

    //The plugin has an underlying resource if it is a workspace plug-in
    IResource r = plugin.getPluginModel().getUnderlyingResource();
    if (r != null){
        r = r.getProject();
        r.accept(new IResourceVisitor() {

            @Override
            public boolean visit(IResource resource) throws CoreException {
                if (resource instanceof IFile){
                    result.add(URI.createPlatformResourceURI(resource.getFullPath().toString(), true));
                    return false;
                }
                return true;
            }
        });
    }else{
        Bundle b = Platform.getBundle(plugin.getId());
        Enumeration&lt;URL&gt; urls = b.findEntries("/", "*.e", true);
        while(urls.hasMoreElements()){
            URL url = urls.nextElement();
            URI uri = URI.createPlatformPluginURI(pluginname+url.getPath(), true);
            result.add(uri);
        }
    }

    return result;

}</pre>
<p>As for normal eclipse plug-ins, if a workspace plug-in exists with the same name as an installed plug-in, the workspace version will be used.</p>
<p>Because EMF needs all resources to be loaded into one resource set to resolve crosslinks, it is advised to use some kind of indexer to reduce load times.</p>
<p><strong>Special case: Xtext</strong></p>
<p>If you&#8217;re using this method with Xtext, some things will become much simpler as it provides you some additional infrastructure compared to EMF. First, you won&#8217;t need to write your own indexing service as Xtext does everything for you from caching to lazy linking. Second, you can implement your own builders as builder participants, which leverages the problem of creating and configuring resource sets and loading resources.</p>
<p>The easiest way to use PDE functionality is to implement the possible crosslinks as scopes:</p>
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false">public class PluginDependencyScope extends AbstractScope {

    private final List&lt;IEObjectDescription&gt; descs = new ArrayList&lt;IEObjectDescription&gt;();

    /**
     * @param parent
     * @param ignoreCase
     */
    public PluginDependencyScope(URI context,ResourceSet resourceset, IScope parent) {
        super(parent, false);
        String projname = context.trimFragment().segment(1);
        List&lt;String&gt; deps = MODembedCore.collectAllDependencies(projname);

        for(String d : deps){
            try {
                for(URI uri : MODembedCore.getVisibleResources(d)){
                    try{
                        Resource r = resourceset.getResource(uri, true);
                        for(EObject eo : r.getContents()){
                            if (eo instanceof Package){
                                String name = ((Package) eo).getName();
                                QualifiedName qname = QualifiedName.create(name.split("\\."));
                                descs.add(EObjectDescription.create(qname, eo));
                            }
                        }
                    }catch(Exception e){

                    }
                }
            } catch (CoreException e) {

            }
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.xtext.scoping.impl.AbstractScope#getAllLocalElements()
     */
    @Override
    protected Iterable&lt;IEObjectDescription&gt; getAllLocalElements() {
        return descs;
    }

}</pre>
<p><strong>Problems</strong></p>
<p>This does the magic, but it&#8217;s not perfect. There are some major flaws which are not easy to deal with:</p>
<ul>
<li>Depending on PDE pulls the entire PDE+JDT into your product even if your user does not intend to use it. This is a minor problem, it just causes overhead on the disk usage.</li>
<li>PDE is defined mainly for Java Plug-in projects. The whole user interface contains items which are meaningless in our special case.</li>
<li>If the user is not familiar with PDE and OSGi concepts, she/he will have a hard time understanding the user interface and the operation of cross-link resolution.</li>
<li>When the user tries to add a plug-in to the dependency list, all installed plug-ins are listed, including platform, PDE, JDT, EMF and other components. It may be hard to tell which plug-in contain models of a specific domain.</li>
</ul>
<p><strong>Conclusion</strong></p>
<p>Functionally, PDE contains everything you will need for partitioning models. If the targeted user base is experienced with eclipse, reusing PDE is an option. If needed, some isses can be worked out with some effort. For example the MANIFEST.MF editor can be replaced with a more domain-specific editor, which can filter out uninteresting plug-ins from the dependency list and include additional information which may needed by your domain.</p>
<p>I&#8217;m using this technique to share some common libraries to users for my own domain-specific language. It&#8217;s better than telling the user to download some files and copy them to the workspace. Let me know if you found better ways.</p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2011/11/reusing-pde-in-modeling-context/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Short story of the day</title>
		<link>http://cubussapiens.hu/2010/06/short-story-of-the-day/</link>
		<comments>http://cubussapiens.hu/2010/06/short-story-of-the-day/#comments</comments>
		<pubDate>Tue, 22 Jun 2010 16:09:47 +0000</pubDate>
		<dc:creator>Zoltán Ujhelyi</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://cubussapiens.hu/?p=1429</guid>
		<description><![CDATA[Never, I mean never write code like this: [cc_java] boolean isRel1 = false, isRel2 = false; if((isRel1 = element1 instanceof IRelation) &#124;&#124; (isRel2 = element2 instanceof IRelation)){ &#8230; } [/cc_java] Especially do not use such code in comparators. If not &#8230; <a href="http://cubussapiens.hu/2010/06/short-story-of-the-day/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Never, I mean never write code like this:</p>
<p>[cc_java]<br />
boolean isRel1 = false, isRel2 = false;<br />
if((isRel1 = element1 instanceof IRelation)<br />
|| (isRel2 = element2 instanceof IRelation)){<br />
&#8230;<br />
}<br />
[/cc_java]</p>
<p>Especially do not use such code in comparators. If not at first try, than later it will mess up things badly, as you rely on the variable, that will not be set because of the evaluation optimization.</p>
<p>This fact cost me three or four hours today&#8230;</p>
<p>A better solution (for those who look for usable code snippets):</p>
<p>[cc_java]<br />
boolean isRel1 = element1 instanceof IRelation;<br />
boolean isRel2 = element2 instanceof IRelation;<br />
if(isRel1 || isRel2) {<br />
&#8230;<br />
}<br />
[/cc_java]</p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2010/06/short-story-of-the-day/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mi a hiba a kódban? #2</title>
		<link>http://cubussapiens.hu/2009/12/mi-a-hiba-a-kodban-2/</link>
		<comments>http://cubussapiens.hu/2009/12/mi-a-hiba-a-kodban-2/#comments</comments>
		<pubDate>Mon, 07 Dec 2009 21:38:46 +0000</pubDate>
		<dc:creator>Zoltán Ujhelyi</dc:creator>
				<category><![CDATA[Fejlesztés]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[programozás]]></category>

		<guid isPermaLink="false">http://cubussapiens.hu/?p=1314</guid>
		<description><![CDATA[A [intlink id="1249" type="post"]múltkori, nagy sikerű írásom[/intlink] hatására Tompika küldött nekem egy hasonlóan izgalmas problémát. [cc_java]while (true) { Process p = Runtime.getRuntime().exec(&#8220;macska&#8221;); p.waitFor(); }[/cc_java] A kód eredeti, Tompika kedvenc állatait, a macskákat felemlegetve. A kód elméletben a következőt kellene, hogy &#8230; <a href="http://cubussapiens.hu/2009/12/mi-a-hiba-a-kodban-2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A [intlink id="1249" type="post"]múltkori, nagy sikerű írásom[/intlink] hatására Tompika küldött nekem egy hasonlóan izgalmas problémát.</p>
<p>[cc_java]while (true) {<br />
Process p = Runtime.getRuntime().exec(&#8220;macska&#8221;);<br />
p.waitFor();<br />
}[/cc_java]</p>
<p>A kód eredeti, Tompika kedvenc állatait, a macskákat felemlegetve. A kód elméletben a következőt kellene, hogy csinálja: az első sor a [cci_java]p[/cci_java] referenciával elérhető módon indít egy processzt; míg a második sor vár, amíg a processz fut.</p>
<p>Ha megnézzük a kapcsolódó JavaDoc kommenteket, ez így működőképes is lehet. Ezzel szemben futásidőben problémák léptek fel, amiket feltehetőleg a következő kódrészletre való kicserélés javított:</p>
<p>[cc_java]while (true)<br />
{<br />
Process p = Runtime.getRuntime().exec(&#8220;macska&#8221;);<br />
p.waitFor();<br />
p.getErrorStream().close();<br />
p.getOutputStream().close();<br />
p.getInputStream().close();<br />
p.destroy();<br />
}<br />
[/cc_java]</p>
<p>A kódrészlet utolsó sora vicces. Idézném a <a href="http://java.sun.com/javase/6/docs/api/java/lang/Process.html#destroy%28%29">Javadoc kommentet</a>:</p>
<blockquote><p>[cci_java]public abstract void destroy()[/cci_java]</p>
<p>Kills the subprocess. The subprocess represented by this   [cci_java]Process[/cci_java] object is forcibly terminated.</p></blockquote>
<p>Amit én úgy értelmeznék, hogy a függvényt meghívva explicite lezárom a Processt. Viszont állítólag nem így történik. Valaki tudja a magyarázatot? Kíváncsi lennék rá.</p>
<p>PS.: ha valaki hozzájut hasonló gyöngyszemekhez, és eljuttatja hozzám, szívesen közzéteszem.</p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2009/12/mi-a-hiba-a-kodban-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Eclipse GEF wtf</title>
		<link>http://cubussapiens.hu/2009/11/eclipse-gef-wtf/</link>
		<comments>http://cubussapiens.hu/2009/11/eclipse-gef-wtf/#comments</comments>
		<pubDate>Tue, 17 Nov 2009 19:25:56 +0000</pubDate>
		<dc:creator>Balage</dc:creator>
				<category><![CDATA[Fejlesztés]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[programozás]]></category>

		<guid isPermaLink="false">http://cubussapiens.hu/?p=1287</guid>
		<description><![CDATA[Az előző kitérő után most térjünk vissza egy kis kocka témához. A minap érdekes felfedezést tettem, miközben véletlenül a GEF belső kódjába tévedtem debug közben. Alapvetően egyébként meg vagyok elégedve a GEF és általában az eclipse platform minőségével, ritka az &#8230; <a href="http://cubussapiens.hu/2009/11/eclipse-gef-wtf/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Az előző kitérő után most térjünk vissza egy kis kocka témához. A minap érdekes felfedezést tettem, miközben véletlenül a GEF belső kódjába tévedtem debug közben. Alapvetően egyébként meg vagyok elégedve a GEF és általában az eclipse platform minőségével, ritka az az eset, hogy a fejemet fogom egy-egy megoldás láttán. </p>
<p>A következő kódrészlet ugyan működik és mivel a publikus api elrejti, az átlag fejlesztő nem találkozik vele, mégis  érdemes rávetni egy pillantást. További szócséplés helyett következzék a kód, szerintem magáért beszél:</p>
<p><code lang="java"><br />
//AbstractEditPart.class</p>
<p>private Object[] policies;</p>
<p>//...</p>
<p>/**<br />
 * @see EditPart#installEditPolicy(Object, EditPolicy)<br />
 */<br />
public void installEditPolicy(Object key, EditPolicy editPolicy) {<br />
	Assert.isNotNull(key, "Edit Policies must be installed with keys");//$NON-NLS-1$<br />
	if (policies == null) {<br />
		policies = new Object[2];<br />
		policies[0] = key;<br />
		policies[1] = editPolicy;<br />
	} else {<br />
		int index = 0;<br />
		while (index < policies.length &#038;&#038; !key.equals(policies[index]))<br />
			index += 2;<br />
		if (index < policies.length) {<br />
			index++;<br />
			EditPolicy old = (EditPolicy)policies[index];<br />
			if (old != null &#038;&#038; isActive())<br />
				old.deactivate();<br />
			policies[index] = editPolicy;<br />
		} else {<br />
			Object newPolicies[] = new Object[policies.length + 2];<br />
			System.arraycopy(policies, 0, newPolicies, 0, policies.length);<br />
			policies = newPolicies;<br />
			policies[index] = key;<br />
			policies[index + 1] = editPolicy;<br />
		}<br />
	}</p>
<p>	if (editPolicy != null) {<br />
		editPolicy.setHost(this);<br />
		if (isActive())<br />
			editPolicy.activate();<br />
	}<br />
}<br />
</code></p>
<p>Akinek nem világos elsőre, kifejteném a problémát: láthatóan egy tömböt használ a java-ban alapértelmezésként elérhető "Map" funkcionalitásának a kiváltására. A tömb páros (és nulladik) helyén szereplő elem tárolja a kulcsot, az utána lévő páratlan helyen lévő elem az érték. </p>
<p>Minden elem hozzáadásakor dinamikusan növeli a tömb méretét, törléskor meg egyszerűen null-ra állítja a tömb megfelelő elemét. Ehhez még társul egy custom iterátor is, ami a tömb nem null elemeit listázza.</p>
<p>Őszintén nem értem a tervezési döntést, ami a tömb-alapú Map-hez vezethetett. A memóriaigénye a HashMap-nek nem sokkal több, és mivel jellemzően kis elemszámú esetek fordulnak elő, ez nem számottevő. A sebessége a HashMap-nek jobb, a "get" és "put" metódusok általános esetben konstans, de mindenképpen kevesebb a tömb végigjárásánál. Mindennek a tetejébe a fenti kód Map alkalmazásával kb. 3 sorra cserélhető, nem beszélve az osztály egyéb kódjáról, ami a tömböt piszkálja.</p>
<p>Egyetlen érthető mentségként csak arra tudok gondolni, hogy esetleg a kód korábban íródott, minthogy a java collections API-ba belekerült volna a Map. Ez viszont az 1.2-es verzióban történt meg, tehát elég régen. Nem tudom mennyi idős a GEF, így ezt nem tudom eldönetni.. Mindenesetre ez a kód nálam megütötte a WTF szintet.</code></p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2009/11/eclipse-gef-wtf/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mi a hiba a kódban?</title>
		<link>http://cubussapiens.hu/2009/10/mi-a-hiba-a-kodban/</link>
		<comments>http://cubussapiens.hu/2009/10/mi-a-hiba-a-kodban/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 20:14:16 +0000</pubDate>
		<dc:creator>Zoltán Ujhelyi</dc:creator>
				<category><![CDATA[Fejlesztés]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://cubussapiens.hu/?p=1249</guid>
		<description><![CDATA[Volt ma egy szép debug köröm. Nagyon nem értettem, miért nem működik egy kód &#8211; ami ráaásul régebben (július végén) szépen ment, és azóta nem nyúltam hozzá, és elvileg a kapcsolódó libekben sem volt lényegi változás azóta. Úgy gondolom, bemutatom &#8230; <a href="http://cubussapiens.hu/2009/10/mi-a-hiba-a-kodban/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Volt ma egy szép debug köröm. Nagyon nem értettem, miért nem működik egy kód &#8211; ami ráaásul régebben (július végén) szépen ment, és azóta nem nyúltam hozzá, és elvileg a kapcsolódó libekben sem volt lényegi változás azóta.</p>
<p>Úgy gondolom, bemutatom a kódot, és felteszem a kérdést, látja-e más is a hibát benne.</p>
<p>[ccw_java]private ICoreNotificationObject notificationObject;</p>
<p>public void actionPerformed(ICoreNotificationObject notification) {<br />
  this.notificationObject = notification;<br />
  Display.getDefault().aSyncExec(new Runnable() {</p>
<p>  public void run() {<br />
    String action = notificationObject.getActionType();<br />
    if (isOneOf(action, new String[] {<br />
          ICoreNotificationObject.TA_TRANSACTION_END,<br />
          ICoreNotificationObject.TA_UNDO_END,<br />
          ICoreNotificationObject.TA_SUBTRANSACTION_END})) {<br />
       updateGraph();<br />
       transactions.pop();<br />
    } else if (isOneOf(action, new String[] {&#8230;}){<br />
       //&#8230;<br />
    }<br />
  });[/ccw_java]</p>
<p>Még némi információ a kód működéséről: a kód egy eseményfigyelő osztály belsejében van, és a Runnable adatváltozásokat próbál követni, amely tranzakciókba van szervezve, ill. a tranzakciók során visszavonás események is érkezhetnek.</p>
<p>Na, kinek van tippje, mi lehet a hiba? Ha nincs tipp véges időn belül (előre nem specifikálnám), akkor majd megosztom a helyes megfejtést. Annyit mondok előre, hogy fejet falbaverős hiba <img src='http://cubussapiens.hu/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  .</p>
<p><strong>Update</strong>: először is helyesbítettem a kódot, mert sikeresen a javított változatot töltöttem fel.</p>
<p>A problémát az okozta, hogy az asyncExec() hívás indított egy új jobot, amit valamikor majd végrehajt. Csak közben visszaadja a vezérlést, és ezzel lehetővé teszi a rendszer számára, hogy felülírja a run() metóduson belül is használt notificationObject változót.</p>
<p>Az asyncExec() hívás syncExec()-re cserélése megoldotta a problémát, ugyanis az megvárja, hogy visszatérjen a meghívott thread.</p>
<p>Ez a hiba kifejezetten mocskos dolog, mert eredetileg működött, míg a környezet refactoringja előhozta a bugot&#8230;</p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2009/10/mi-a-hiba-a-kodban/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java konstruktor hívási sorrend</title>
		<link>http://cubussapiens.hu/2009/09/java-konstruktor-hivasi-sorrend/</link>
		<comments>http://cubussapiens.hu/2009/09/java-konstruktor-hivasi-sorrend/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 21:05:12 +0000</pubDate>
		<dc:creator>Balage</dc:creator>
				<category><![CDATA[Fejlesztés]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[programozás]]></category>

		<guid isPermaLink="false">http://cubussapiens.hu/?p=1219</guid>
		<description><![CDATA[Rég írtam, valóban. Hogy újra rávezessem magam a kedvenc munkán kívüli elfoglaltságomhoz, most egy egyszerűbb témát vetek fel, ami mégis okozott pár kobak-koppanást az asztalon. Nevezetesen arról szándékozom írni, hogy a Java hogyan sorrendezi egy objektum inicializálásában résztvevő kódokat. Mert &#8230; <a href="http://cubussapiens.hu/2009/09/java-konstruktor-hivasi-sorrend/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Rég írtam, valóban. Hogy újra rávezessem magam a kedvenc munkán kívüli elfoglaltságomhoz, most egy egyszerűbb témát vetek fel, ami mégis okozott pár kobak-koppanást az asztalon. Nevezetesen arról szándékozom írni, hogy a Java hogyan sorrendezi egy objektum inicializálásában résztvevő kódokat. Mert bizony több lehet, és nem egyértelmű a lefutási sorrend, ahogy azt a követkető kódrészlet szemlélteti:</p>
<p><code lang="java"><br />
public class AB{<br />
	public static abstract class A{<br />
		public A(){<br />
			doSomething();<br />
	    }<br />
	    protected abstract void doSomething();<br />
	}</p>
<p>	public static class B extends A{<br />
		final String s = "1234";<br />
		final Object o = "1234";<br />
	    public B(){<br />
	    	super();<br />
	    }<br />
	    @Override<br />
	    protected void doSomething(){<br />
	    	System.out.println(s.getClass());<br />
	    	System.out.println(o.getClass());<br />
	    }<br />
	}</p>
<p>	public static void main(String[] args){<br />
	    new B();<br />
	}<br />
}<br />
</code></p>
<p>A példát igyekeztem egyszerűnek tartani, de talán megérdemel egy rövid magyarázatot: Két osztályt definiáltam, az egyik leszármazottja a másiknak. Érdekesség még, hogy az ős konstruktora kódot hív meg a leszármazottból absztrakt metóduson keresztűl. Egy &#8220;B&#8221; típusú objektum létrehozásához láthatóan három helyről kell kódot hívni: Az &#8220;A&#8221; és a &#8220;B&#8221; konstruktora, továbbá a &#8220;B&#8221; osztályban lévő, konstruktoron kívüli inicializálás. A probléma ezen három kódrészlet lefutásának sorrendje.</p>
<p>Első ránézésre a kóddal semmi probléma nincs azon kívül, hogy teljesen haszontalan. Mindkét mező final, így gondolnánk a konstruktor elött inicializálódnak, tehát nem okozhat problémát. Azonban a kód futtatásakor egy csinos NullPointerException kacsint vissza ránk. A futás kimenete:</p>
<p><code><br />
class java.lang.String<br />
Exception in thread "main" java.lang.NullPointerException<br />
	at AB$B.doSomething(AB.java:22)<br />
	at AB$A.<init>(AB.java:8)<br />
	at AB$B.</init><init>(AB.java:17)<br />
	at AB.main(AB.java:27)<br />
</init></code></p>
<p>Láthatóan a B.doSomething() első sora lefut hiba nélkül, a probléma utána keletkezik. Tehát az &#8220;s&#8221; változó már létezik, az &#8220;o&#8221; viszont nem. A konstruktorok lefutásának sorrendje tehát: s=..,A(),o=..,B(). A két mező között csupán az a különbség, hogy az &#8220;s&#8221; mező típusa megegyezik a futásidejű értékének típusával. Ez meghatározza, hogy a mező a szülő osztály konstruktora előtt vagy után kap értéket. Érdemes kipróbálni, ha az &#8220;s&#8221; mező elöl kivesszük a final kulcsszót, az azt okozza, hogy az is a szülő konstruktor hívása után kap értéket. Vajon hogy határozódik meg a pontos sorrend, mitől függ, hogy hova ütemezi be a java a mezők értékadását? </p>
<p>Nyílván valahogy igyekszik meghatározni, hogy az adott értékadás kiértékelhető-e az osztály örökölt részének inicializálása nélkül vagy sem. Ennek tesztelésére tettem még egy kísérletet, kicsit módosítva a példát:</p>
<p><code lang="java"><br />
public class AB{<br />
	public static abstract class A{<br />
		protected String a;<br />
		public A(){<br />
			a = "abc";<br />
			doSomething();<br />
	    }<br />
	    protected abstract void doSomething();<br />
	}</p>
<p>	public static class B extends A{<br />
		final String s = "1234"+a;<br />
		final Object o = "1234";<br />
	    public B(){<br />
	    	super();<br />
	    }<br />
	    @Override<br />
	    protected void doSomething(){<br />
	    	System.out.println(s.getClass());<br />
	    	System.out.println(o.getClass());<br />
	    }<br />
	}</p>
<p>	public static void main(String[] args){<br />
	    new B();<br />
	}<br />
}<br />
</code></p>
<p>Ez a kód is szépen elszáll, méghozzá a B.doSomething() első sorában! Azaz, az explicit hivatkozás egy szülő objektum-beli elemre azt eredményezi, hogy a mező értékadását a szülő konstruktor utánra ütemezi. Elég intelligensnek tűnik a dolog, de mégis beleütközik az ember, mert másra számít. </p>
<p>Persze elkerülhető a dolog ha a konstruktorból hívott absztrakt metódusokat anti-pattern-nek kiáltjuk ki, bár gyakran jól jön. Mégis pontosan mi határozza meg a sorrendet, és lehet-e befolyásolni valahogyan? Van valaki aki nálam sikeresebben guglizott?</p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2009/09/java-konstruktor-hivasi-sorrend/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Java kimenet UTF-8 kódolásban &#8211; második felvonás</title>
		<link>http://cubussapiens.hu/2008/09/java-kimenet-utf-8-kodolasban-masodik-felvonas/</link>
		<comments>http://cubussapiens.hu/2008/09/java-kimenet-utf-8-kodolasban-masodik-felvonas/#comments</comments>
		<pubDate>Mon, 22 Sep 2008 18:30:52 +0000</pubDate>
		<dc:creator>Balage</dc:creator>
				<category><![CDATA[Fejlesztés]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[kompatibilitás]]></category>
		<category><![CDATA[utf8]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Ezt nem lehet megunni, újra és újra hasonló problémákba ütközök. Most kivételesen nem parancssorban kellett UTF-8 kimenetet generálnom, hanem a Java 6 beépített HTTP szerveréről a kliens felé adott generált válaszban merült fel ugyanez a probléma. A különös az volt, hogy működött, mindenféle konverzió nélkül, tehát teljesen nyugodt voltam, hogy ez a kódrészletet jól írtam meg. Órákba tellet rájönnöm, hogy ez a feltételezés hibás volt.
 <a href="http://cubussapiens.hu/2008/09/java-kimenet-utf-8-kodolasban-masodik-felvonas/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ezt nem lehet megunni, újra és újra hasonló problémákba ütközök. Most kivételesen nem parancssorban kellett UTF-8 kimenetet generálnom, hanem a Java 6 beépített HTTP szerveréről a kliens felé adott generált válaszban merült fel ugyanez a probléma. A különös az volt, hogy működött, mindenféle konverzió nélkül, tehát teljesen nyugodt voltam, hogy ez a kódrészletet jól írtam meg. Órákba tellet rájönnöm, hogy ez a feltételezés hibás volt.<br />
<!--break--><br />
A problémakör egyszerű, bár érdekes. Widget-alapú AJAX-os webalkalmazást fejlesztek az önálló laboromhoz, de erről később. A lényeg az, hogy amikor a felhasználó csatlakozik a szerverhez, az egy generált HTML oldallal válaszol, és minden további feladatra JavaScript kódot küld, amit a kliens lefuttat. A javascript kódban a szövegeket előrelátóan <a href="http://hu.wikipedia.org/wiki/Base64">Base64</a> kódolásban vittem át, így ezekkel probléma nem volt. Nem ez volt a helyzet azonban a generált HTML kóddal. Arra lettem figyelmes, hogy a webalkalmazást megváltoztatva a böngészőben nem jelenik meg semmi..</p>
<p>A helyzet felettébb furcsa volt, a generálás során nem merült fel hiba, sőt, a generált kimenet a szerver oldalon jó volt és az átvitel sem dobott kivételt. A kliens oldalon megérkeztek a fejléc sorai, de nem kapott kimenetet. Nem értettem a problémát, hiszen addig jó volt, és azon a részen nem változtattam. Hosszas próbálgatás és debugolás után rájöttem, hogy a hiba megjelenése erősen korrelál azzal a ténnyel, hogy a generált kimenetben szerepel-e ékezetes karakter. Ekkor merült fel bennem, hogy a probléma a kódolással van.</p>
<p>Tehát, a megoldás az, hogy előkeresem a [intlink id="556" type="post"]korábbi cikkemet[/intlink], és az ott szereplő megoldást extrapolálom az én esetemre. Azaz, amikor a <a href="http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/HttpExchange.html#getResponseBody()">HttpExchange kimeneti adatfolyamát</a> lekérem, egy egyszerű <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/PrintStream.html">PrintStream</a> helyett a következő módon wrappolom, és a böngészőt is értesítem róla, hogy milyen kódolásban kap adatot:</p>
<p><code lang="java"><br />
PrintStream out =  new PrintStream(arg0.getResponseBody(),true,"UTF-8");<br />
arg0.getResponseHeaders().add("Content-Type","text/html; charset=UTF-8");<br />
</code></p>
<p>A nagyobbik fejtörést az okozta, hogy még így se működött, a hiba ugyanaz maradt, csak annyi változott, hogy a <a href="https://addons.mozilla.org/en-US/firefox/addon/60">Web dev toolbar</a> már kijelezte az újonann beadott header sort is. Ekkor megakadt a szemem a következő soron:</p>
<p><code lang="java"><br />
arg0.sendResponseHeaders(200, text.toCharArray().length);<br />
out.print(text);<br />
</code></p>
<p>Ezzel ugye elküldöm a kliensnek hibakódot (200 = OK), illetve a küldött tartalom hosszát. Ez automatikusan hozzáad egy &#8220;Content-Length&#8221; sort a header-ekhez. Amikor ezt írtam, jó ötletnek tünt. De! A java belső UCS kódolásában a karakterek száma nem egyezik meg a byte-ok számával a karakterlánc UTF-8 -beli kódolásában. A megoldás: a sendResponseHeaders() metódus második argumentuma legyen 0. Ez azt jelenti, hogy tetszőleges hosszúságú tartalmat küldhetünk el, a bytesorozat végét az jelzi, hogy bezárjuk a kapcsolatot.</p>
<p>Így tényleg működik. csak az érdekesség kedvéért egy rövid idézet a <a href="http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/HttpExchange.html">HttpExchange dokumentációjából</a>:</p>
<pre>"If the call to sendResponseHeaders() specified a fixed response body length, then the exact number of bytes specified in that call must be written to this stream. If too many bytes are written, then write() will throw an IOException. If too few bytes are written then the stream close() will throw an IOException. In both cases, the exchange is aborted and the underlying TCP connection closed."</pre>
<p>Hogy mi ezzel a probléma? Csak az, hogy a dokumentáció szerint kivételt kellett volna kapnom, amikor úgy zárom le, hogy a küldött byte-ok száma nem egyezik az előre megadottal. Ez viszont nem történt meg, hanem egy furcsa, és visszakövethetetlen hibajelenségbe ütköztem. Talán gyorsabban megtalálom a hibát, ha kapok egy értelmes hibaüzenetet.</p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2008/09/java-kimenet-utf-8-kodolasban-masodik-felvonas/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>2D adatszerkezet modellezése Javában</title>
		<link>http://cubussapiens.hu/2008/09/2d-adatszerkezet-modellezese-javaban/</link>
		<comments>http://cubussapiens.hu/2008/09/2d-adatszerkezet-modellezese-javaban/#comments</comments>
		<pubDate>Thu, 18 Sep 2008 21:00:49 +0000</pubDate>
		<dc:creator>thSoft</dc:creator>
				<category><![CDATA[Fejlesztés]]></category>
		<category><![CDATA[adatszerkezet]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[tervezés]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[&#8230;avagy hogyan lehet pozitív tulajdonság a gyengeség és a lustaság. Arról a gyakran előforduló modellről van szó, amikor sorok és oszlopok metszeteiben rácselemek csücsülnek, melyek automatikusan létrejönnek a nekik megfelelő sor-oszlop párra való hivatkozáskor, valamint automatikusan megszűnnek soruk vagy oszlopuk &#8230; <a href="http://cubussapiens.hu/2008/09/2d-adatszerkezet-modellezese-javaban/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>&#8230;avagy hogyan lehet pozitív tulajdonság a gyengeség és a lustaság. <img src='http://cubussapiens.hu/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Arról a gyakran előforduló modellről van szó, amikor sorok és oszlopok metszeteiben rácselemek csücsülnek, melyek automatikusan létrejönnek a nekik megfelelő sor-oszlop párra való hivatkozáskor, valamint automatikusan megszűnnek soruk vagy oszlopuk törlése esetén.<br />
A megvalósítás kézenfekvőnek tűnik: a sorokban/oszlopokban egy map-ben tároljuk az oszlopokkal/sorokkal indexelve a rácselemeket.<br />
<!--break--><br />
Valahogy így:<br />
[cc_java]<br />
public class Node {<br />
}</p>
<p>public class Column {<br />
}</p>
<p>public class Row {</p>
<p>protected final Map nodes = new HashMap();</p>
<p>public Map getNodes() {<br />
  return nodes;<br />
}</p>
<p>}<br />
[/cc_java]</p>
<p>Mi a gond ezzel?</p>
<ul>
<li>Ha törlünk egy oszlopot, az összes sor map-jében még ott marad a rá mutató referencia, mint kulcs. Ez memory leakhez vezet: a szemétgyűjtő nem tudja eltakarítani a &#8220;zombi&#8221; oszlopokat és a hozzájuk tartozó, ugyancsak zombi rácselemeket. Ez ráadásul az adatstruktúra perzisztálásánál is problémát jelent.</li>
<li>Hogyan s mikor hozzuk létre a rácselemeket? Mindig, amikor létrehozunk egy oszlopot? Ezt jobban lehetne automatizálni, ráadásul ha nem minden rácspontba akarunk elemet tenni, fölöslegesen hozzuk létre ezeket.</li>
</ul>
<p>Több megoldás is lehetséges, gondolhatnánk elsőre:</p>
<ul>
<li>Gondolkodhatnánk egy címkézett gráfban, és a beépített kollekciók helyett alkalmazhatnánk valamiféle gráfkezelő könyvtárat, pl. a <a href="http://jgrapht.sourceforge.net">JGraphT</a>-t, mely gondoskodik csúcs törlésekor a hozzá tartozó élekről.</li>
<li>Kibővíthetnénk a lista adatszerkezetet eseménykezelőkkel, melyek elem hozzáadásakor és törlésekor végrehajtanak egy megadott kódot.</li>
</ul>
<p>Azonban a probléma megoldható a Java Collections Framework keretein belül, karöltve természetes kiegészítőjével, a <a href="http://larvalabs.com/collections">Collections Generic</a> API-val (a <a href="http://jakarta.apache.org/commons/collections">Commons Collections</a> generikus változata). Nehogy már egy ilyen általános jelenséget ne tudjunk a megannyi hasznos absztrakciót tartalmazó Java nyelv elemeivel modellezni! A kulcsfogalom a <em><a href="http://java.sun.com/javase/6/docs/api/java/lang/ref/WeakReference.html">gyenge referencia</a></em>, mellyel befolyásolhatjuk a garbage collector működését, ezzel rábízva az elárvult elemek törlését.</p>
<p>Javában az alapértelmezett referencia erős (strong), de ezenkívül még létezik a gyenge (weak), lágy (soft) és fantom (phantom) referencia. A weak reference lényege, hogy amennyiben egy objektumra csak ilyenek mutatnak, a szemétgyűjtő teljes lelki nyugalommal eltakarítja. Nekünk pont ez a viselkedés jön kapóra: a map-ben gyenge referenciákat fogunk csak tárolni az oszlopokra/sorokra. (A másik két típus most nem érdekes számunkra, pedig azok is hasznosnak bizonyulhatnak más esetekben.)</p>
<p>A Collections API tartalmazza a <a href="http://java.sun.com/javase/6/docs/api/java/util/WeakHashMap.html">WeakHashMap</a> osztályt, mely a <a href="http://java.sun.com/javase/6/docs/api/java/util/HashMap.html">HashMap</a>-hez hasonló, azonban kulcsai gyenge referenciák. A WeakHashMap ezeket átlátszóan kezeli, önmagától létrehozva és dereferálva nekünk őket. Így programunkban az automatikus törléshez csak két dolgot kell módosítanunk: HashMap helyett WeakHashMap-et használunk, és a kívánt pillanatban meghívjuk a garbage collectort.</p>
<p>A létrehozás pedig <em>lusta map</em> segítségével történik: a rácselemek példányosítása akkor és csak akkor történik, amikor először hivatkozunk az őket azonosító sor-oszlop párosra. Ehhez is kész eszközt kapunk a kezükbe a Collections Generic Libraryben: a <a href="http://collections.sourceforge.net/api/org/apache/commons/collections/map/LazyMap.html">LazyMap</a>-et és az <a href="http://collections.sourceforge.net/api/org/apache/commons/collections/functors/InstantiateFactory.html">InstantiateFactory</a>-t, melyek a Decorator és a Factory pattern alkalmazásával érik el céljukat.</p>
<p>Imhol a forráskód módosított része. Figyelemreméltó, hogy mennyi minden változott&#8230;<br />
[cc_java]<br />
public class Row {</p>
<p>protected final Map nodes = LazyMap.decorate(new WeakHashMap(), new InstantiateFactory(Node.class)); // !</p>
<p>}<br />
[/cc_java]</p>
<p>És egy kis tesztosztály, a kiértékelés a kedves olvasó feladata:<br />
[cc_java]<br />
public class GridTest {</p>
<p>public static void main(String[] args) {<br />
  Grid grid = new Grid();<br />
  for (int i = 0; i &lt; 2; i++) {<br />
    grid.getRows().add(new Row());<br />
    grid.getColumns().add(new Column());<br />
  }<br />
  for (Row row : grid.getRows()) {<br />
    for (Column column : grid.getColumns()) {<br />
      System.out.println(row.getNodes().get(column));<br />
    }<br />
  }<br />
  grid.getColumns().remove(1);<br />
  System.gc(); // !<br />
  for (Row row : grid.getRows()) {<br />
    for (Column column : row.getNodes().keySet()) {<br />
      System.out.println(row.getNodes().get(column));<br />
    }<br />
  }</p>
<p>}</p>
<p>}<br />
[/cc_java]</p>
<p>Hát ilyen power a Collections Framework, amint már Stampie is [intlink id="587" type="post"]rámutatott[/intlink], ami pedig esetleg hiányzik belőle, azt a Collections Generic pótolja. Mi a tanulság? Használjuk ki a nyelvi lehetőségeket, amelyek rendelkezésünkre állnak!</p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2008/09/2d-adatszerkezet-modellezese-javaban/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Platformfüggő fejlesztés Java-ban</title>
		<link>http://cubussapiens.hu/2008/08/platformfuggo-fejlesztes-java-ban/</link>
		<comments>http://cubussapiens.hu/2008/08/platformfuggo-fejlesztes-java-ban/#comments</comments>
		<pubDate>Sat, 30 Aug 2008 17:06:42 +0000</pubDate>
		<dc:creator>Zoltán Ujhelyi</dc:creator>
				<category><![CDATA[Fejlesztés]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[probléma]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Ritka eset, hogy szükségünk van rá, de velem megesett. Szükségem volt a java-t futtató rendszer típusára és architektúrájára. Ráadásul futásidőben. Az ok egyszerű. SWT alkalmazást fejlesztek, és nem akarok minden platformra külön kiadást csinálni, ne a felhasználó találja ki, hogy milyen rendszert futtat. De ez mellékes, a probléma adott, futásidőben kell meghatározni, melyik platformfüggő csomagot töltsem be?
 <a href="http://cubussapiens.hu/2008/08/platformfuggo-fejlesztes-java-ban/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ritka eset, hogy szükségünk van rá, de velem megesett. Szükségem volt a java-t futtató rendszer típusára és architektúrájára. Ráadásul futásidőben. Az ok egyszerű. SWT alkalmazást fejlesztek, és nem akarok minden platformra külön kiadást csinálni, ne a felhasználó találja ki, hogy milyen rendszert futtat. De ez mellékes, a probléma adott, futásidőben kell meghatározni, melyik platformfüggő csomagot töltsem be?<br />
<!--break--><br />
Egyszerű a megoldás &#8211; írják a lelkes és segítőkész, ám nem teljesen tájékozott fórumozók &#8211; A <code lang="java">System.getProperty()</code> paranccsal le lehet kérni a szabványosított, így minden JVM-ben létező &#8220;os.name&#8221;, &#8220;os.version&#8221; és &#8220;os.arch&#8221; tulajdonságokat, amikkel egyszerű beazonosítani a futtató rendszert. A szabvány valóban rögziti, hogy milyen tulajdonságmezőknek kell lenniük, azonban ezeknek a lehetséges értékeit nem. Most jön csak a szenvedés.</p>
<p>A kisebb problémát az &#8220;os.name&#8221; mező jelenti, ami többé-kevésbé konzisztens értékeket ad vissza a Sun és az alternatív<fn>Ezen a ponton megjegyezném, hogy csak abból az egyszerű tényből kifolyólag hívom a nem a Sun által készített JVM-eket alternatívoknak, mert a Java nyelv szabványát a Sun saját szabványügyi hivatala adja ki. Az igazsághoz hozzátartozik, hogy az említett hivatal úgy jött létre, hogy az ISO visszadobta a Java szabványt, és a Sun ezt a megoldást találta ki a nyelv szabványosítására.</fn> JVM-eknél is. Ezek közül egyetlen kakukktojás a Windows (mi más), aminek minden verziójához tartozik egy saját &#8220;os.name&#8221; érték, és ezen felül az &#8220;os.version&#8221; is tartalmazza a rendszer ritkábban látott verziószámát. Hogy ezzel mi a gond? Csupán az, hogy az 1.5-ös JVM a Vista-t &#8220;Windows NT (Unknown)&#8221;-nak hívja, míg az 1.6-os rendesen &#8220;Windows Vista&#8221;-nak. Értelmesebb lett volna, ha a &#8220;Mac OS&#8221; / &#8220;Mac OS X&#8221;-hez hasonlóan külön jelzik a rendszer két fő ágát, és a verziószám ad bővebb információt a rendszer mibenlétéről. Más rendszerek (pl. Linux) esetén a helyzet jobb, ott tényleg nincs eltérés a verziók között. Íme egy rövid felsorolás az &#8220;os.name&#8221; lehetséges értékeiről: [[http://mindprod.com/jgloss/properties.html#OSNAME]]</p>
<p>Ennél sokkal komolyabb fejtörést okoz a rendszer architektúrájának meghatározása. Ennél rendkívül változatos értékeket tapasztaltam különböző gépeken, rendszertől függetlenül. Még a Sun JVM-ek se konzisztensek ebben. Az még nem túlzottan meglepő, hogy a 64 bites, intel-alapú rendszeremet &#8220;amd64&#8243;-nek hívja, hiszen a disztróm hivatalosan amd64-re van fordítva. Más gépeken viszont szinte véletlenszerűen kerül elő a fent említett megnevezés mellett &#8220;x86_64&#8243;, illetve &#8220;x64&#8243; is. További érdekesség, hogy mivel &#8220;Mac OS X&#8221;-en még nincs 64 bites 1.6os Java, így azt &#8220;i386&#8243;-osnak jelzi. Ebből látszik, hogy a kérdéses mező nem a rendszer, hanem a JVM tulajdonságát adja vissza. Ennél a pontnál elérkeztünk a régebbi, 32 bites rendszerekhez, ami lehet &#8220;x86&#8243;, &#8220;i386&#8243;, &#8220;i686&#8243;, és hasonszőrű társai bármelyike. Utolsóként megemlíteném a Power PC architektúrát, ami lehet &#8220;ppc&#8221;, vagy &#8220;PowerPC&#8221; elnevezésű is.</p>
<p>A fenti mezők értékeire vonatkozólag láthatóan a Sun berkein belül sincs megegyezés, különböző rendszereken, vagy akár csak különböző verziók más-más értéket adhatnak. A legnagyobb probléma mégis az, hogy ez nincs sehol dokumentálva! A néhány kicsit használható gyűjteményt lelkes felhasználók hozták össze, de ezek hiányosak, és/vagy régen frissültek. Íme az általam talált legjobb, ami határozottan kevés: [[http://lopica.sourceforge.net/os.html]].</p>
<p>Végső megoldás lehet kitaposott úton járni, azaz felhasználni egy már létező megoldást, ami talán megmondja, mégis milyen rendszeren vagyok. Hasonló megoldásokban szinte kizátólagosan az [[http://lopica.sourceforge.net/os.html|Ant]] projekt kerül szóba, ami tartalmaz egy osztályt, mely egy szimpla enumerált értéket állít elő a létező operációs rendszereknek megfelelően. Az &#8220;os.arch&#8221; változót pedig csak nemes egyszerűséggel kivezeti a felhasználó számára az összes JVM tulajdonsággal egyetemben. Továbbá az Ant csak fordítás-idejű megoldást kínál, ezzel én nem lettem okosabb.</p>
<p>Végső elkeseredésemben azon kezdtem agyalni, hogy a program első futásakor végigpróbálgatom az összes rendelkezésre álló SWT lib-et, és amelyik nem dob kivételt, az működik. Ha ehhez hozzávesszük, hogy felismerhetünk pár &#8220;os.name&#8221;, &#8220;os.arch&#8221; értéket, akkor nem is olyan elvetemült ötlet.</p>
<h3>(Update) A megoldás</h3>
<p>[[http://cubussapiens.hu/user/30|Happy]] [[http://cubussapiens.hu/node/593#comment-117|hozzászólása]] alapján a zseniálisan egyszerű megoldás:</p>
<p><code lang="java"><br />
package proba;</p>
<p>import org.eclipse.core.runtime.internal.adaptor.EclipseEnvironmentInfo;</p>
<p>public class EnvInfo {</p>
<p>	/**<br />
	 * @param args<br />
	 */<br />
	public static void main(String[] args) {<br />
		// TODO Auto-generated method stub<br />
		EclipseEnvironmentInfo eei = EclipseEnvironmentInfo.getDefault();<br />
		System.out.println(eei.getWS()+"."+eei.getOS()+"."+eei.getOSArch());<br />
		System.out.println(eei.getNL());<br />
	}</p>
<p>}<br />
</code></p>
<p>, ami nálam a következő kimenetet adja:</p>
<p><code><br />
linux.gtk.x86_64<br />
hu_HU<br />
</code></p>
<p>Stampie jól gondolta, ezt a problémát már megoldották az Eclipse-ben, csak akkor én ezt nem találtam meg. Az [[http://mobius.inria.fr/eclipse-doc/org/eclipse/core/runtime/internal/adaptor/EclipseEnvironmentInfo.html|EclipseEnvironmentInfo]] osztály a org.eclipse.osgi_3.4.0.v20080605-1900.jar csomagban található meg, és ez az swt csomagok elnevezésével kompatiblis jelölésekkel adja meg a rendszer jellemzőit.</p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2008/08/platformfuggo-fejlesztes-java-ban/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Java rendezés &#8211; avagy hogyan ne tegyük</title>
		<link>http://cubussapiens.hu/2008/08/java-rendezes-avagy-hogyan-ne-tegyuk/</link>
		<comments>http://cubussapiens.hu/2008/08/java-rendezes-avagy-hogyan-ne-tegyuk/#comments</comments>
		<pubDate>Thu, 14 Aug 2008 16:15:30 +0000</pubDate>
		<dc:creator>Zoltán Ujhelyi</dc:creator>
				<category><![CDATA[Fejlesztés]]></category>
		<category><![CDATA[adatszerkezet]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[A Java Collection könyvtára remek munka - könnyen használható, mégis sokoldalú API-t biztosít. Megfelelő listákhoz, gráfreprezentációkhoz és feltételezem, hogy még sok minden egyébhez.

Ehhez képest nem (sokkal) bonyolultabb kezelni, mint egy tömböt. Sőt, a C nyelv tömbkezeléséhez képest sokkal egyszerűbb is... :-)

Ami nekem különösen tetszik, az a beépített rendezési lehetőségek: a <em>Collections.sort</em> statikus metódus használatával saját <em>Comparator</em> segítségével lehet rendezéseket definiálni.
 <a href="http://cubussapiens.hu/2008/08/java-rendezes-avagy-hogyan-ne-tegyuk/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A Java Collection könyvtára remek munka &#8211; könnyen használható, mégis sokoldalú API-t biztosít. Megfelelő listákhoz, gráfreprezentációkhoz és feltételezem, hogy még sok minden egyébhez.</p>
<p>Ehhez képest nem (sokkal) bonyolultabb kezelni, mint egy tömböt. Sőt, a C nyelv tömbkezeléséhez képest sokkal egyszerűbb is&#8230; <img src='http://cubussapiens.hu/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Ami nekem különösen tetszik, az a beépített rendezési lehetőségek: a <em>Collections.sort</em> statikus metódus használatával saját <em>Comparator</em> segítségével lehet rendezéseket definiálni.</p>
<p>Ezután szinte magától adódott már, hogy amikor nekem egy objektumhierarchia reprezentálására van szükségem, akkor ahhoz ezt a beépített könyvtári osztályokat használjam. Az általam használt algoritmus (most ezt nem részletezném a szükséges tömörség miatt) feltételezte, hogy a hierarchia elemeit felülről lefelé adom be (azaz mindig előbb az őst adom be, és csak utána a leszármazottakat). Miután ezt a bemenetemről nem tudtam feltételezni, ezért adódott a dolog, írjunk rá egy rendezést, saját komparátorral.</p>
<p><code lang="java5">public int compare(IEntity i1, IEntity i2){<br />
	            if (i1.isSubtypeOf(i2)) return -1;<br />
            else if (i2.isSubtypeOf(i1)) return 1;<br />
                        else return i1.getFullyQualifiedName().compareTo(i2.getFullyQualifiedName());<br />
                                }</code></p>
<p>Szép, olvasható kód, és pontosan azt írja le, amit szeretnék. Igaz? Hisz itt látszik, hogy szépen az öröklési hierarchia szerint rendezi a mezőket. Amikor ezt a kódot úgy nagyjából egy hónapja megírtam, akkor működött is &#8211; igaz, csak erőteljesen korlátozott tesztelés volt, mert ez csak egy nagyon parányi része volt a dolognak, amit csináltam, és utána pedig egy kicsit ezt a részt jegeltem.</p>
<p>Ehhez képest most jött a feketeleves, hogy amikor egy kicsit változott a környezet, amiben az új funkciót teszteltem, kaptam egy hatalmas nullpointer exception-t. Remek&#8230;</p>
<p>Némi játék után (ugyanis a futási környezet lenyelte a kivételt, és csak az üzetenet jelenítette meg, ami nullpointer exception-nél mindig &#8220;&#8221;, azaz nem látszik), kiderítettem, hogy a gondot az okozza, hogy egy objektum kapcsán próbálok hivatkozni az ősére egy saját adatszerkezetben, de ebbe az adatszerkezetbe nem került bele. Ez pedig csak úgy lehetséges, ha az eredeti rendezésnél valami miatt a leszármazott előbbre kerül, mint az őse (általában nem, de az én programomban igen).</p>
<p>Kíváncsi vagyok, hogy hány ember látja, hogy hol is van a probléma a fenti komparátorral, hogyan jöhet össze, hogy a beépített Java sort algoritmus is ezt a rossz eredményt adja ki&#8230;</p>
<p>Tökéletes magyarázatom nincs a problémára, de a hiba oka nagyjából két dolog lehet. Egyfelől a definiált komparátor csak egy részben rendezéshez ad megfelelő támpontot, másrészt a Java feltehetőleg a qsort algoritmust használja, ami nem végzi el az összehasonlítást az összes párra, így tipikusan nem hasonlít össze minden egyes elemet minden másik elemmel.</p>
<p>Van még egy tényező, ami a rendezési eljárást még kevésbé  egyértelművé teszi, ez pedig az egymástól akár teljesen független ágak a hierarchiában. Az eredeti példáimban ezekből kevés volt, míg a példa, amin kiakadt a program, viszonylag sok, egymástól független ágat tartalmazott, ezzel jócskán megnehezítve az algoritmus munkáját.</p>
<p>Ötletem nem volt, hogyan kellene működővé varázsolni a rendezést egy átírt komparátorral, ezért más, korábbi tanulmányokhoz nyúltam vissza: a bsz-en/algoritmuselméleten bemutatott topologikus rendezéshez nyúltam vissza. Ugyan az jóval erősebb rendezési feltétel, mint amire nekem konkrétan szükségem volna, de ezért cserébe viszonylag kevés munkával lekódolható, és nem is túlságosan lassú (jó, ez persze relatív).</p>
<p>Persze ennek a kódolásakor is segítségemre volt a Java Collections API, még így is kevesebb, mint 20 sor volt a teljes rendezési eljárás, amit még zárásnak beszúrok az írás végé elé.</p>
<p><code lang="java5">	/**<br />
	 * Creates a topological ordering on the modelelements<br />
	 */<br />
	private List<IEntity> orderModelElements(List<IEntity> elementsToOrdered){</p>
<p>		List<IEntity> orderedElements = new ArrayList<IEntity>();<br />
		while (!elementsToOrdered.isEmpty()){<br />
			//The currentLevel is needed in order to remove all the elements that<br />
			//do not have any ancestors, not only the first one<br />
			//If we delete the elements straight from the elementsToOrdered list,<br />
			//the iterator in the for cycle will not work.<br />
			List<IEntity> currentLevel = new ArrayList<IEntity>();<br />
			for (IEntity element : elementsToOrdered){<br />
				Collection<IModelElement> ancestors = new ArrayList<IModelElement>();<br />
				ancestors.addAll(element.getSupertypes());<br />
				ancestors.retainAll(entities);//remove all non-entities<br />
				if (ancestors!=null &#038;&#038; orderedElements.containsAll(ancestors)){<br />
					currentLevel.add(element);<br />
				}<br />
			}<br />
			orderedElements.addAll(currentLevel);<br />
			elementsToOrdered.removeAll(currentLevel);<br />
		}<br />
		return orderedElements;<br />
	}<br />
</code></p>
<p>És hogy miért is írtam ezt így ide meg? Ennek két oka is van: egyrészt egy nagyon önző, magamat szem előtt tartó indok: ha valaki el tudja esetleg mondani nekem, hogyan kellene a komparátort kijavítani, esetleg részletesebben elmagyarázza csak, hogy miért is hasal el az a komparátor a quick sorton (ha quick sort), nagy örömmel veszem akármilyen formában a reakcióját. Másfelől pedig okulásnak is akart menni mások számára, hogy esetleg nekik ne kelljen órákat bogarászniuk egy pár ezer soros kódbázisban, hogy pontosan hogyan is adódhat az a nullpointerexception.</p>]]></content:encoded>
			<wfw:commentRss>http://cubussapiens.hu/2008/08/java-rendezes-avagy-hogyan-ne-tegyuk/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

