tag:blogger.com,1999:blog-20793366031460899922024-03-04T21:11:48.953-08:00Hardnox JavaJ2EE, ADF, Weblogic and everything else Java and J2EE can do for a working man.Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.comBlogger11125tag:blogger.com,1999:blog-2079336603146089992.post-71993574058686412242010-09-27T12:38:00.000-07:002010-09-27T13:28:19.774-07:00RichFaces media output. Why not? Here is why.So, few words about RichFaces. You know the general details, of course, and I'm sure Google is of more help than I am on that and many other matters. From my experience, it is very usable, easy to start with, with nice skinning mechanism and very usable default skins (unlike IceFaces, for instance). Since ADF is proprietary framework (and good luck with finding anyone willing to pay license for it), it only makes sense comparing it to IceFaces. It is more stable, has quite larger community (I didn't count, but searching for problems and answers on the web was pretty easier for RichFaces). As everything else, both IceFaces and RichFaces have a few quirks, and noting them all would take some time, so I have chosen the one that gave us the most trouble. <div><br /></div><div>RichFaces mediaOutput component, as you can see in live demo, can be useful for displaying various media content you generate, as said on the linked page, "on the fly". Sure, it worked quite well in the demo, but once we started using it in our application, it turned out to be quite a burden.</div><div><br /></div><div>I noticed something was wrong when I tested it in Internet Explorer. The damn browser still holds quite a bit of a market, although competition is numerous and, in my opinion, better. Firefox is my default browser for about five years, and I am satisfied with it, although since my recent purchase of a Macbook, Safari became my primary browser (I simply like the cover flow stuff) although Firefox is still used from time to time and is a default system browser (mostly for my home projects). But using Firefox in a corporate environment is still novelty new in my country, and some companies simply have company standards which require MS technologies, including IE (even in version 6.0!). So, you simply can't avoid browser compatibility.</div><div><br /></div><div>Browser compatibility hurts like hell. CSS stuff has always been a challenge for browser compatibility and things didn't get better with xFaces frameworks. Because of their relying on a bundle of styles and JavaScript, it is a very sensitive matter. You will often have a very nice working page in Firefox, Chrome and even Opera, but in IE it will cause a number of errors, usually indicated only by message in lower left corner. When you open that message, you will see something saying that there is an error in ".../a4jsf/93hjd90u39j93e3e/homeiu384.js", somewhre deep in RichFaces source. Of course, other browsers can also cause similar problems, but on our project, it turned out that IE is the biggest problem, at least for working with components from RichFaces. </div><div><br /></div><div>We had a need for pop-up window which displays contents of remote HTML or PDF files. Pop-ups in RichFaces are implemented as panels which are shown/idden using JavaScript (wrapped up in RichFaces whith convinient show() and hide() functions, as you can see in the examples). We followed the examples from livedemo website, and soon had nice working example of MediaOutput in Firefox, Chrome and Opera. Unfortunately, IE simply showed blank window. Google, RichFaces forums, Ilya and everything else didn't give any other aswer than "It works in our examples in livedemo". Sure, if our applications were that simple as demos. Don't get me wrong, your own messed up forms and can cause trouble which some browser can tolerate, and some can not. For instance, thanks to templates, includes and our carelessness, we had a case of nested forms (a big no-no), which was tolerated by Firefox, but Chrome just stopped rendering a page and showed error output. So it would be wrong to blame framework and RichFaces developers (who have done quite a job) for everything that has gone wrong. But in this case, MediaOutput did not work in IE.</div><div><br /></div><div>We have lost quite a lot of time and finally implemented our functionality using simple HTML OBJECT. Works everywhere. In fact, RichFaces eventually transforms your mediaOutput component into OBJECT so the result is the same, only RichFaces gets sometimes lost in the way. </div><div><br /></div><div>I still recommend RichFaces for JSF frameworks. It is good, nice looking, but it is nice to know it's limitations. But the only way to get to that is by painful experience. But that is our job. My motto, which is popular children song sang during kids games, describes our programming work: "Kolariću, paniću, pletemo se samiću,<b> sami sebe zaplićemo, sami sebe rasplićemo...</b>". The bold part, in Serbian, says:"<i>we tangle ourselves, we untangle ourselves</i>". I think you get it :)</div><div><br /></div><div><br /></div><div><br /></div><div>P.S.</div><div>As for ADF, well, it has taken a few years of my life, been a good experience... I wonder if I will be using it again. It is browser-safe, obviously well tested, pricey, and, taken in account ADF bindings and data controls, good only if you have well defined and stable architecture underneath (yeah, business components). </div>Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com0tag:blogger.com,1999:blog-2079336603146089992.post-54997098445932790272010-09-27T04:02:00.000-07:002010-09-27T04:12:17.285-07:00Difference in comparin Integer between JDK 1.6.0_11 and JDK 1.6.0_18Quite busy summer, but just to post quick info about thing that happened to me a moment ago.<br /><br />I develop application on a Windows machine, test it etc. and once a day I deploy it to our Linux server for our testers. You know those situations "App works perfectly on my machine, but crashes in production"? Well, after checking parameters and other config stuff, I turned myself to my Log4j trace (yeah, should have done that first) and it turned out that certain validation of mine fails. <br />It compares two Integer values, in this example 37 and 37, by using != operator.<br /><br />So, machine A, JDK 1.6.0_18, a == b returns true<br />Machine B, JDK 1.6.0_11 a==b returns false.<br /><br />where a and b are Integer(37).<br /><br />Safe way, of course, is using equals method, or comparing by intValue property.<br /><br />A lot of interesting stuff about RichFaces in my project has happened this summer, but I leave that for some other time. Deadlines and stuff, you know :)Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com0tag:blogger.com,1999:blog-2079336603146089992.post-65722487448521498612010-06-06T01:56:00.000-07:002010-06-06T02:31:21.446-07:00JBoss and RichFaces: jsf libs and errorsDefinitely: just following manual is just not enough. So we waste our working days on stuff like this...<br /><br />Recently I started working on JBoss/RichFaces platform for a new application. I was following the instructions from RichFaces website, and added the jars<span style="font-style: italic;"></span> they said were necessary. It worked well on Tomcat, but it didnt go that wel on JBoss. It resulted in exceptions like this:<br /><br /><em>ConfigurationException</em>: <em>CONFIGURATION FAILED</em>! <em>null</em> at <em>com.sun.faces.config.</em><div class="s"><wbr><em>ConfigManager.initialize</em>(<em>ConfigManager</em>.<em>java</em>:<em>213</em>)...<br /><br /><br />with a long stack trace, of course... Stack trace didn't point to any configuration error, just this null pointer exception. So, after some Google-ing, I saw that it is a common problem, some are lucky to get a few pointers from stack trace, but some just get this null and are stuck. Fortunately, a few guys pointed out that the problem might be with the jfs libraries.<br /><br />So, what really happens is that libraries that I have put in WEB-INF/lib folder conflict with JBoss JSF libraries already present on server. Libraries in question are jsf-api, jsf-impl and jsf-facelets jars. Problems might arise from the fact that versions of user provided and server provided libraries are not the same, or that interfaces of some required libraries are not appropriate for some other in combination.<br /><br />So, my first step was to replace those jars with the one present in JBoss server libs (simple search through jars in JBoss with TotalCommander gives you location of libs, packed in JBoss war-s or some similar archive ). It didn't quite work. Obviously, if i deploy app war with the same libraries, the problem remains.<br /><br />So, I then removed the jsf libs from web-inf/lib. It worked to a point where I started using jsf functions in my code (like FacesContext.getCurrentInstace()....) , where I needed jsf jars in project. But I don't want tohose jars in my war. So, what to do?<br /><br />Solution is quite simple. Instead of placing jars yourself, you just add JBoss Server LIbrary to your project's build path in Eclipse. (Properties->Configure Build Path...). Your project has all required dependencies for development, and deployed app has the same enviroment like during deployment. You can check through libraries to see if there are any other unnecessary duplicates.<br /><br /></div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6k-Qw6ZJIu2ejwY1ws_xFkIQqg6ESH_QR2nv9IWG4_0jNjEwHrT7FwoFvmfVoZR12SM00Yp04CEz6P5zxXy8fh5wq5Wqddr22D7LFhF-CCbcp8kmAAFGGzy2e2gAtxsnOlvLHl4TTHcY/s1600/jbossbuildpath.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 376px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6k-Qw6ZJIu2ejwY1ws_xFkIQqg6ESH_QR2nv9IWG4_0jNjEwHrT7FwoFvmfVoZR12SM00Yp04CEz6P5zxXy8fh5wq5Wqddr22D7LFhF-CCbcp8kmAAFGGzy2e2gAtxsnOlvLHl4TTHcY/s400/jbossbuildpath.JPG" alt="" id="BLOGGER_PHOTO_ID_5479589981836149906" border="0" /></a><br /><br /><br />So,Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com1tag:blogger.com,1999:blog-2079336603146089992.post-85461839885561527222010-02-25T10:51:00.000-08:002010-05-06T05:51:49.224-07:00Eclipselink: table sequence generator and concurrency - Part ThreeThanks to eager readers, I finally got to finish this :D<br /><br />So far, last two posts showed that there is a problem with sequencing in eclipselink regarding concurrent access and that there is a possibility of implementing custom sequence generator. We decided to to our own implementation of table generated sequence.<br /><br />So, as we said, we have our own sequence generator class which is, interestingly, called CustomSequenceGenerator:<br /><br />As you can see, getGeneratedValue method is used to get concrete value. There an instance of CustomSequenceManager class is used. Of course, it is used in our<br /><br />public class CustomSequenceGenerator extends Sequence implements SessionCustomizer {<br />private Logger logger = Logging.getLogger(CustomSequenceGenerator.class);<br /><br />private CustomSequenceManager customSequenceManager;<br />public CustomSequenceGenerator() {<br /> super();<br /> logger.debug("CustomSequenceGenerator()");<br /> customSequenceManager = new CustomSequenceManager();<br /> logger.debug("new CustomSequenceManager()");<br />}<br /><br />public CustomSequenceGenerator(String name) {<br /> super(name);<br /> logger.debug("CustomSequenceGenerator(String name)");<br /> customSequenceManager = new CustomSequenceManager();<br /> logger.debug("new CustomSequenceManager()");<br />}<br /><br />@Override<br />public Object getGeneratedValue(Accessor accessor,<br /> AbstractSession writeSession, String seqName) {<br /> logger.debug("getGeneratedValue()");<br /> Long nextValue = customSequenceManager.getNextValue(seqName);<br /> logger.debug("nextValue = " + nextValue);<br /> return nextValue;<br />}<br /><br />@Override<br />public Vector getGeneratedVector(Accessor accessor,<br /> AbstractSession writeSession, String seqName, int size) {<br /> return null;<br />}<br /><br />@Override<br />protected void onConnect() {<br />}<br /><br />@Override<br />protected void onDisconnect() {<br />}<br /><br />@Override<br />public boolean shouldAcquireValueAfterInsert() {<br /> return false;<br />}<br /><br />@Override<br />public boolean shouldOverrideExistingValue(String seqName,<br /> Object existingValue) {<br /> return existingValue == null;<br />}<br /><br />@Override<br />public boolean shouldUseTransaction() {<br /> return false;<br />}<br /><br />@Override<br />public boolean shouldUsePreallocation() {<br /> return false;<br />}<br /><br />public void customize(Session session) throws Exception {<br /> logger.debug("customize(Session session) ");<br /> CustomSequenceGenerator sequence = new CustomSequenceGenerator("BASE_ENTITY_SEQ");<br /> logger.debug("new CustomSequenceGenerator('BASE_ENTITY_SEQ')");<br /> session.getLogin().addSequence(sequence);<br /> logger.debug("session.getLogin().addSequence(sequence)");<br />}<br /><br />}<br /><br /><br />Now, let's see CUstomSequenceManager class. What we do is just simulate the sequencing as we know it in Oracle.<br /><br />public class CustomSequenceManager {<br /> private static Logger logger = Logger .getLogger(CustomSequenceManager.class);<br /> protected HashMap<string,> sequenceMap = new HashMap<string,>();<br /> //Saves values for frame limits<br /> private Long allocationSize = MyParameters.getSequenceFrameSize();<br /> protected HashMap<string,> sequenceFrame = new HashMap<string,>();<br /> <br /> public synchronized Long getNextValue(String seqName){<br /> SequenceService sequenceService = new SequenceService();<br /><br /> Long seqCount = sequenceMap.get(seqName);<br /> Long seqLimit = sequenceFrame.get(seqName);<br /> <br /> if(seqCount == null || seqCount == seqLimit-1){<br /> seqCount = sequenceService.getCustomSequenceNextValue(seqName);<br /> if(seqCount == null){<br /> seqCount = 0L;<br /> }<br /> seqLimit = seqCount + allocationSize;<br /> <br /> sequenceFrame.put(seqName, seqLimit);<br /> sequenceMap.put(seqName, seqCount);<br /> }<br /> else if(seqCount<=seqLimit-1){<br /> seqCount++;<br /> sequenceMap.put(seqName, seqCount);<br /> }<br /><br /> <br /> return seqCount;<br /> }<br />}<br /><br />I guess it's easy to follow. We allocate frame of values and use the values from it. when we exceed the frame values, we get the next frame etc. We use hash map for storing current values, and we get new frame values from SequenceService.<br /><br /><br />public class SequenceService {<br /> SequencePersist sequencePersist;<br /> <br /> public SequenceService (){<br /> try {<br /> Context ctx = new InitialContext();<br /> sequencePersist = (SequencePersist) ctx.lookup("SequencePersistBean");<br /><br /> } catch (javax.naming.NamingException ne) {<br /> throw new EJBException(ne);<br /> }<br /> }<br /> <br /> public UserSequence create(UserSequence s){<br /> <br /> return sequencePersist.create(s);<br /> }<br /> public UserSequence modify(UserSequence s){<br /> return sequencePersist.modify(s);<br /> }<br /> public UserSequence find(String seqName){<br /> Object seqObj = sequencePersist.find(seqName);<br /> if(seqObj == null){<br /> return null;<br /> }<br /> return (UserSequence)seqObj;<br /> }<br /> public List findQuery(String queryString){<br /> return sequencePersist.findQuery(queryString);<br /> }<br /> public Long getCustomSequenceNextValue(String seqName){<br /> return sequencePersist.getCustomSequenceNextVal(seqName);<br /> }<br /> <br />}<br /><br />Nothing special here, because all the work is done behind SequencePersist interface. Here we used EJB implementation, but you can also use Spring to get bean. What is really important is in SequencePersistBean implementation, and that is database access to sequence table.<br /><br />@Stateless(name="SequencePersistBean")<br />public class SequencePersistBean implements SequencePersistLocal,SequencePersistRemote{<br />@PersistenceContext(name = "my_sequence/EntityManager",<br /> unitName = "my_sequence")<br /> EntityManager em;<br /> Logger logger = Logger .getLogger(SequencePersistBean.class);<br /> <br /> public SequencePersistBean(){<br /> <br /> }<br /> @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)<br /> public UserSequence create(UserSequence s){<br /> em.persist(s);<br /> return (UserSequence)em.find(s.getClass(), s.getSeqName());<br /> }<br /> @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)<br /> public UserSequence modify(UserSequence s){<br /> return (UserSequence)em.merge(s);<br /> }<br /> @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)<br /> public UserSequence find(String seqName){<br /> Object seqObj = em.find(UserSequence.class, seqName);<br /> if(seqObj == null){<br /> return null;<br /> }<br /> return (UserSequence)seqObj;<br /> }<br /> @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)<br /> public List findQuery(String queryString){<br /> return (List) em.createQuery(queryString).getResultList();<br /> }<br /> @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)<br /> public Long getCustomSequenceNextVal(String seqName){<br /> Long sequenceCount = null;<br /> try{<br /> StoredProcedureCall spcall = new StoredProcedureCall();<br /> spcall.setProcedureName("CC1NextSequenceVal");<br /> spcall.addNamedArgument("SequenceName");<br /> spcall.addNamedOutputArgument(<br /> "NextValue", // procedure parameter name<br /> "NextValue", // out argument field name<br /> BigDecimal.class // Java type corresponding to type returned by procedure<br /> );<br /> <br /> ValueReadQuery query = new ValueReadQuery();<br /> query.setCall(spcall);<br /> query.addArgument("SequenceName"); // input<br /><br /> List args = new ArrayList();<br /> args.add(seqName);<br /> <br /> <br /> Session session = JpaHelper.getEntityManager(em).getActiveSession();<br /> logger.debug("session" + session);<br /> BigDecimal intSeq = (BigDecimal) session.executeQuery(query, args);<br /> sequenceCount = intSeq.longValue();<br /> }catch(RuntimeException e){<br /> logger.fatal("getCustomSequenceNextVal", e);<br /> }<br /> logger.debug("sequenceCount" + sequenceCount);<br /> return sequenceCount;<br /> }<br />}<br /><br /><br />As you can see, @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) denoting methods is used to guarantee that each call is done in separate transaction.<br /><br />I won't get into too much details about seuence table, because it is just imitation of Ewclipselink generated table. We use bean's methods to modify values in the table.<br /><br /><br />getCustomSequenceNextVal method is interesting, because we use stored procedure to ensure complete transaction isolation on database level. This Java code should be universal on all databases that have stord procedures and are supported by EclipseLink. The final touch is done writing stored procedure, which is DB thing. We used Oracle, so procedure is written as autonomous, on other database you should make something equivalent.<br /><br />So, the essence of the matter is that you take frame of N values from DB table, store it in Java Hash map where you read and increment values. When you exceed the frame, you go to the DB to get new values. Reading through stored procedure that is autonomous will ensure that every concurrent reader gets different frame value. Basically, procedure looks in the table for row with specific SEQ_NAME. From the same row reads the value, and frame size and returns it. Then it increments value for frame, stores it, and that is it. Everything that Eclipselink table generated sequence should do, but doesn't for some reason.</string,></string,></string,></string,>Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com2tag:blogger.com,1999:blog-2079336603146089992.post-63054009104258861212009-12-14T13:55:00.000-08:002009-12-28T02:21:17.759-08:00Eclipselink: table sequence generator and concurrency - Part Two, Custom Sequence generatorIn my previous post I explained how EclipseLink TableGenerated primary keys have a problem with concurency. I'm not sure why and whether other people had the same problem, but what can you do? Well, we had to do something.<br /><br />First, I cosidered possibility of different configuring of primary key generation straegy for different platforms, using master entity superclass and confguring with XML descriptors (actually combining XML descriptors and annotations).<br /><br />The, I tried to find some solution that enables us to somehow make EclipseLink use some alternative method of primary key generation. Fortunately, it did not take long.<br /><br />On <a href="http://wiki.eclipse.org/EclipseLink/Examples/JPA/CustomSequencing">EclipseLink wiki</a> there is an example of custom sequencing using UUID. Now, UUID generation is something we came across while using Hibernate, who has some issues using HashMaps and identifying objects, so generating UUID used in isEqual methods for objects is very recommender. Using UUID as primary key sounded interesting, but, frankly, I did not feel like modifying database schema...<br /><br />So I wondered, why not making my own, concurrency safe version of table sequencing? After all, it is very nice solution, takes my mind of thinking whether I use MS, Oracle or whatever DB and I dont bother worrying over whether identity columns will do just as good job as Oracle sequences...<br /><br />Let's look into customizing sequencing.<br /><br />You can extend Eclipselink classes Sequence and StandardSequence. You also have to implenent SessionCustomizer interface.<br /><br /><pre class="source-java"><span class="kw2">public</span> <span class="kw2">class</span> UUIDSequence <span class="kw2">extends</span> <span class="kw3">Sequence</span> <span class="kw2">implements</span> SessionCustomizer{</pre><br />Now, look into the class. For us important methods are<br /><br /><pre class="source-java"><span class="kw2">public</span> <span class="kw3">Object</span> getGeneratedValue<span class="br0">(</span>Accessor accessor,<br /> AbstractSession writeSession, <span class="kw3">String</span> seqName<span class="br0">)</span> <span class="br0">{</span><br /> <span class="kw2">return</span> UUID.<span class="me1">randomUUID</span><span class="br0">(</span><span class="br0">)</span>.<span class="me1">toString</span><span class="br0">(</span><span class="br0">)</span>.<span class="me1">toUpperCase</span><span class="br0">(</span><span class="br0">)</span>;<br /> <span class="br0">}</span><br /></pre>and<br /><br /><pre class="source-java"><span class="kw2">public</span> <span class="kw4">void</span> customize<span class="br0">(</span>Session session<span class="br0">)</span> <span class="kw2">throws</span> <span class="kw3">Exception</span> <span class="br0">{</span><br /> UUIDSequence sequence = <span class="kw2">new</span> UUIDSequence<span class="br0">(</span><span class="st0">"system-uuid"</span><span class="br0">)</span>;<br /><br /> session.<span class="me1">getLogin</span><span class="br0">(</span><span class="br0">)</span>.<span class="me1">addSequence</span><span class="br0">(</span>sequence<span class="br0">)</span>;<br /> <span class="br0">}</span><br /><br /><span class="br0"></span></pre>getGeneratedValue method, well, returns the generated sequence value in whatever way we want. In the example UUID is used, so simply radnom generated uuid value is returned from the method.<br /><br />But, how do we make Eclipselink use our sequence generator? customize method is used for this. As you can see, a new instance of our sequence class is created <span style="font-weight: bold;">with our specific name</span> given to constructor, and our sequence is added to session. To tell eclipselink that we are using our custom generator we add a property in the persistence unit<br /><br /><div dir="ltr" style="text-align: left;"><pre class="source-xml"><span class="sc3"><span class="re1"><property></property></span> <span class="re0">name</span>=<span class="st0">"eclipselink.session.customizer"</span> <span class="re0"><br /> value</span>=<span class="st0">"eclipselink.example.UUIDSequence"</span><span class="re2">/></span></span></pre></div>Where value of the property is full qualified class name of our Sequencing class.<br /><br />And that is it. I'm not really sure how this works, but persistence unit sees that it has customizable class, method customize is called and our sequence is set. When you want to use sequence in your JPA entities, you siply specify name you passed to constructor<br /><br /><pre class="source-java">@Id<br />@GeneratedValue<span class="br0">(</span>generator=<span class="st0">"system-uuid"</span>/><br />@Column<span class="br0">(</span>name=<span class="st0">"PROJ_ID"</span><span class="br0">)</span><br /><span class="kw2">private</span> <span class="kw4">int</span> id;</pre><br />In the next post we will make similar class which will use our own table generated sequence. And yes, it is quite simple :)<br /><br />Wow, not bad post after 10 days of flu...Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com3tag:blogger.com,1999:blog-2079336603146089992.post-43457938180327176622009-11-25T04:26:00.001-08:002009-11-30T04:04:42.242-08:00Eclipselink: table sequence generator and concurrency - Part OneWhy do we like OR mapping? OK, you got tons of advertising written about that, so take your pick.<br />For your boss most likely most interesting thing would be universal database connectivity. You have customers with various databases, so it is much easier to sell your software. You dont have to buy a licence for a new database, relax, we got them all covered... Actually, that was our case.<br /><br />OK, that is cool. We had our little piece of software up and running on Eclipselink (I had quite an adventure on migrating from Hibernate, but that is another story). Since we wanted to be database vendor independent, we chose table generated ID's for our primary keys.<br /><br />Little intro, just to put some light on it, but I'm sure you guru's out there don't need it ;) <a href="http://wiki.eclipse.org/EclipseLink/Examples/JPA/PrimaryKey">Here</a> is a good place to start. There you can find details on ID generation strategies.<br /><br />When you specify an entity in JPA, you have to set one of the class fields as an ID, using annotation @Id.<br /><br />So the next step is to see how to assign those ID's. You could set values yourself before persisting an object, but that is not very useful in practice. There are also options for using identity or sequencing, but this is not applicable on all databases. For instance, identity columns are available in SQL Server, but Oracle uses sequences. If you want universal solution, portable on all databases, you need table generated primary keys. It is similar to Oracle sequences, only the values are stored in a user table Eclipselink is accessing. If you use schema generation, Eclipselink will, according to your annotations, generate that table. Usually table has columns for sequence name and value, allocation size (default 50). If you look into the documentation on <span style="font-weight: bold;"><span style="font-weight: bold;">@TableGenerator </span></span>annotation, you will see that you can configure name for this table, its columns, and also values for allocation size etc.<br /><br />So it all sounded nice. And on Hibernate it worked nice. But life just isn't that simple. Life is fun.<br /><br />While doing some stress testing on some application modules I became aware of an unpleasant fact that unusual number of unique constraints is occuring.<br /><br />What I did was that I deployed application module and set up some 5 clients on others computers to target it with a large number of subsequent requests which typically did some inserting and updating in the database. Then it turned out that I get a relatively large number of unique constraint errors - on primary keys!<br /><br />So, 5 clients target EJB modules, services in modules access database using Eclipselink. New objects are generated and mapped into tables. When persisting objects, Eclipselink takes tabel generated value and assigns it as objects ID. INsert into... And same thing happens initiated from several clients. One should expect that Eclipselink gives different values for primary keys each time new object is persisted. It shoul handle concurrency. But it looks like it does not.<br /><br />Of course, we have checked our test cases and they were OK. It works just fine in a single client situation. When we addes another client, only 4-5 unique constraints occured on some 10000 inserts. Adding new clients increased exoenentially number of exceptions.<br /><br />I have written few words to Oracle, on official forum as well on Metalink (now Oracle Support). Well, guys told me that it it shouldn't happen. But it does. It is not anything exotic - stateless session beans, jpa persistence using eclipselink provider on Weblogic server. You look up bean, method creates and persists object. It is not clustered environment.<br /><br />I would really like to know if anyone else had similar problem, so if you hear anything... :)<br /><br />Then search for alternative methods for generating ID's started. After a while, it turned out that Eclipselink is flexible enough to give us opportunity to use our own ID generation mechanism.<br /><br />Next post will be really interesting one, when I present our cool solution :DMiloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com3tag:blogger.com,1999:blog-2079336603146089992.post-23572654743028109142009-11-25T03:54:00.000-08:002009-11-25T04:26:00.842-08:00Eclipselink: Null primary key encountered in unit of work clone<pre class="bz_comment_text">Remember that XKCD strip about the most boring guy in the world and his blog<br />where he only apologizes for not writing more? :D Here it is ;)</pre><br />Well, it's been a while. To be honest, civilian military service is not actually best environment for us developers, but what can you do, from June next year, I'm back on track.<br /><br />Meanwhile, a blast from the past. I received a notification about a bug on Eclipselink you can find <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=249948">here</a>. Of course, I encountered it last summer. Suddenly a weird error Null primary key encountered in unit of work clone, as the title of this post (I hope it helps with google).<br /><br />So, this is one of those things that just frustrates you. You develop application, write queries by the book, OK, push the limits probably on few fronts, but it's all according to specification, should work, wright? Yeah, should. But bug like this just kills you. It occurs seemingly randomly, fires up nad causes some null pointer exceptions in upper layers of your application, so you dig in and find thing like this. I can tell you, I've been lucky here. In most cases I just run (actually Google does) into two or three guys who had the same problem (usually our Corean brotheren, hats off ! ), and no solution...<br /><br />So, it had something to do with assigning sequence numbers. I went so far to dig into the source code of Eclipselink, but honestly, I couldn't get my way around it, even debugging (I'm not proud) didn't help. Guys who discussed the problem on the thread about the bug suggested that the problems are negative ID's which could not occur in our application. At the end, we've given up. And now the blessed news:<br /><br /><span style="font-style: italic;" class="bz_comment_user"><span class="vcard"><span class="fn">Chris Delahunt</span> </span> </span> <span style="font-style: italic;" class="bz_comment_user_images"> </span> <span style="font-style: italic;" class="bz_comment_time"> 2009-11-12 16:13:34 EST </span> <pre class="bz_comment_text"><span style="font-style: italic;">Peter checked in a fix 02 November 2009</span><br /><br />I'll check it with the guys at work to see if they still have the same problem<br />as before and if new patch will help.<br /><br />This reminds me of a very interesting problem tha led to very<br />interesting solution,regarding sequencing, concurency and<br />multiplatform implementation of JPA.<br />Interested? Well, OK, you will have it in the next blog post which,<br />I hope will not be seven months from now . :)<br /><br /><br /><br /></pre>Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com5tag:blogger.com,1999:blog-2079336603146089992.post-59683052509927329352009-02-14T09:22:00.000-08:002009-02-14T09:56:22.327-08:00How we handled ADF SecurityWell. we're handling it, alright.<br /><br />One of the things you must take into account is that developing in JDeveloper with integrated WLS has advantages, but it can be living hell when you try to move application to standalone server. I guess development environment gives you some advantages by setting some things where they should be so you can focus on programming itself. And that is cool. What is not cool is that some of the details remain hidden from you, so you can easily overlook them.<br /><br />As for ADF Security and moving it to other environments, I found <a href="http://andrejusb.blogspot.com/2009/01/practical-adf-security-deployment-on.html">this </a>very helpfull. Andrejus gives you nice step-by-step introduction, with pointing to relevant articles and tutorials from Oracle. But...<br /><br />What wasn't said, or maybe I have missed it, was that you have to put adf-config.xml file on the classpath. If you download Andrejus' example, when you make a deloyment EAR you will see that there is a directory adf with META-INF directory that has connections.xml and, most important, adf-config.xml<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwwxNln_qMN6mOt8TiBjYNoxM7ixgGMMKnIO1NsbBjV3Z3GaqwA8C3Kxqrj8j_x2CvqQTQqx3bUboPC_5vLcOgn7IP_zPRPMiCO-Q1ZhdzpM5BU7Yu29iJmbO1WVCFwAQAFfh68mWF2UY/s1600-h/Untitled.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 247px; height: 196px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwwxNln_qMN6mOt8TiBjYNoxM7ixgGMMKnIO1NsbBjV3Z3GaqwA8C3Kxqrj8j_x2CvqQTQqx3bUboPC_5vLcOgn7IP_zPRPMiCO-Q1ZhdzpM5BU7Yu29iJmbO1WVCFwAQAFfh68mWF2UY/s400/Untitled.jpg" alt="" id="BLOGGER_PHOTO_ID_5302709770901580450" border="0" /></a><br />adf-config.xml has few things you need for using ADF Security.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrYmtFkQXolBkpzPS7vOGxxOSueTxtDv42orT7WtmIDuK7GByoXHZTF8rXFOj5ApCSD58mUGldMGft_22gzTCym4yfeJPeJsUm3WoCw2pEd6rmw4wiglV11R3RPLAB3GEZUv-X5UVDw4Q/s1600-h/Untitled2.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 105px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrYmtFkQXolBkpzPS7vOGxxOSueTxtDv42orT7WtmIDuK7GByoXHZTF8rXFOj5ApCSD58mUGldMGft_22gzTCym4yfeJPeJsUm3WoCw2pEd6rmw4wiglV11R3RPLAB3GEZUv-X5UVDw4Q/s400/Untitled2.jpg" alt="" id="BLOGGER_PHOTO_ID_5302710571638530066" border="0" /></a><br />Of course, you can find enough documentation on this.<br /><br />And this is put to our classpath by using adf-loc.jar that is in the lib directory of EAR. This jar contains only META-INF with manifest file containing this<br /><br />Manifest-Version: 1.0<br />Class-Path: ../adf<br /><br /><br />So that does the trick.<br /><br />But, now what?<br /><br />First, I don't like this restarting server part. It means that changing policies during production requires migration process and restarting server, which I think no one likes. I guess that integrating previous Oracle technologies with WLS has just begun, this has to be corrected ASAP.<br /><br />Second, I guess there aren't many people whith knowledge from both worlds (Oracle and BEA), which will probably change in time. Until then, we have to handle things like this.<br /><br />Anyway, I would like to thank Andrejus for his article and his lovely example that showed me the light.<br /><br />Cheers!Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com1tag:blogger.com,1999:blog-2079336603146089992.post-33574142029738913732009-02-12T02:32:00.000-08:002009-02-12T02:48:32.304-08:00Some trouble with AWT libraries on LinuxOur application is fine, thanks for asking. Our painfull security problem is gone, which will probably be the topic of next posto. But here is the fresh problem and a fresh solution.<br /><br /><br />Our app is using some fancy graph solutions for displaying some statistical data form the application. We are using some ADF stuff, there are some cute controls to help you with that. We are developing on Windows, so the test servers were there. So, today is the big day when I am setting up some VMs for live testing and we are using Linux on them. WLS is installed, domain configured (actually, I just copied domain folder from Windows to Linux and changed paths etc. also an interesting topic) . Server started, I go to a login page, log in, I get main window whith menus and wait for my graphs to be rendered... And the, exception printed on the console, my session breaks and I am returned to the login page!<br /><br />Here are the interesting parts from stacktrace:<br /><br />SEVERE: Server Exception during PPR, #1<br />javax.servlet.ServletException: java.lang.InternalError: Can't connect to X11 window server using 'centosbi.antegra.com:99' as the value of the DISPLAY variable<br /><br />java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11GraphicsEnvironment<br /><br />X11? WTF?<br /><br /><br />Google is my best friend, so I came up with some pointers quite fast:<br /><br /><a href="http://forums.sun.com/thread.jspa?threadID=280804&start=0&tstart=0">link1</a><br /><br />So, it turns out that if I use something from AWT, I need X environment. No way! Well, the guys suggested xvfb solution, which didnt make me very happy... But some guy suggested to set java parameter<br /><br />-Djava.awt.headless=true<br /><br />So I tried that. I set it into setDomainEnv.sh file like java property in line JAVA_OPTIONS=...<br /><br /><br />And it worked.<br /><br /><br />So, if you use Oracle graphical components for rendering bars, pie charts etc. on Linux, you better set this parameter.<br /><br />Cheers!Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com2tag:blogger.com,1999:blog-2079336603146089992.post-85534566352903882342009-02-01T23:42:00.000-08:002009-02-02T00:43:53.686-08:00Basic EclipseLink persistence.xml configurationRight,let's start with the basics.<br /><br />Weblogic has inherited from it's previous versions O/R mapping called KODO. I don't have much to say about it, but it is default ORM for Weblogic, just as Toplink was for OC4J or HIbernate is for JBoss. Of course, JPA is implemented on all of these platforms, and the implementation is done in these persistence mappers. You should try to use JPA as much as possible, and use HIbernate/EclipseLink specifics only where you don't have any other choice. Simple rule, but as always, the problem is judging when to do that. We will say more about it in some other post.<br /><br />Let's get back to persistence.xml. Since default ORM for Weblogic is KODO, if you try to use persistence.xml you used on OC4J,<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh32-Gbv1acr2sLxun1iHN0X3ynGFFeZNO14wHziaU4yEolNFDaY9ju4XTGHKqyoqFof6vyjK3UssbAtxgvMg3jRykTV19JoKdD3E7opGPaoCNGuHuIR7WRHrm-RoBirNJgvJx_ntkA_ug/s1600-h/ScreenShot001.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 430px; height: 225px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh32-Gbv1acr2sLxun1iHN0X3ynGFFeZNO14wHziaU4yEolNFDaY9ju4XTGHKqyoqFof6vyjK3UssbAtxgvMg3jRykTV19JoKdD3E7opGPaoCNGuHuIR7WRHrm-RoBirNJgvJx_ntkA_ug/s320/ScreenShot001.jpg" alt="" id="BLOGGER_PHOTO_ID_5298116173866307666" border="0" /></a><br /><br />Here we used addidtional properties for generating tables based on our JPA entities. It can be useful in development. Of course, not in production, you don't want to drop all tables when you deploy application. Note here that on Toplink we had to excplicitly say type of databse so this would work. We also specified logging level for toplink.<br /><br />Weblogic will assume that it should use default ORM, KODO. Then you will see some KODO specific messages, and things will work... To a certain point.<br /><br />As it turned out, regardless of JPA standard, implementations are not perfect. The last thing you need is changing ORM in the middle of the project (believe me, Hibernate, Toplink... I know!). If you developed with Toplink so far, you should stick to what you know. So we want to stick to Toplink which meanwhile became EclipseLink. OK, you get it with new Weblogic. Now we just have to put couple more things in persistence.xml<br /><span style="color: rgb(51, 51, 153);font-size:78%;" ><persistence xsi="http://www.w3.org/2001/XMLSchema-instance" schemalocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"><persistence-unit name="pu"><properties><property name="eclipselink.ddl-generation" value="drop-and-create-tables"><property name="eclipselink.ddl-generation.output-mode" value="database"><property name="eclipselink.target-server" value="WebLogic"><property name="eclipselink.logging.level" value="FINE"></property></property></property></property></properties></persistence-unit></persistence></span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcSYF5c3FAmRB7lSXtVjv9akjqrB2uvuC4MqTDGXi5OE362aw3GPtrsr0cZH8I-YMU3SlBS1dix90Ii28FSP0dbNmGZCIsyqZvb42shSBRm2VXP7RwguK5f0SG1sHrVPnrb4DCm-z5EyE/s1600-h/ScreenShot002.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 212px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcSYF5c3FAmRB7lSXtVjv9akjqrB2uvuC4MqTDGXi5OE362aw3GPtrsr0cZH8I-YMU3SlBS1dix90Ii28FSP0dbNmGZCIsyqZvb42shSBRm2VXP7RwguK5f0SG1sHrVPnrb4DCm-z5EyE/s400/ScreenShot002.jpg" alt="" id="BLOGGER_PHOTO_ID_5298117153265501298" border="0" /></a><br /><br /><br /><br />Note couple of things. First, we had to tell Weblogic what persistence provider we want to use:<br /><span style="font-size:100%;"><br /></span><span style="color: rgb(51, 51, 153);font-size:100%;" > <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider></span><br /><br />Make sure you put it right after persistence-unit tag.<br /><br />Second, name of eclipselink properties are equivalent to toplink properties. Where once was toplink, now is eclipselink. Same thing goes for most of the classes, package naming etc. So all of this makes transition from Toplink to Eclipselink on Weblogic quite simple. Until we get to classloading and structuring our EAR for new platform.<br /><br />That is another story.<br /><br />Hope this helps someone!Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com0tag:blogger.com,1999:blog-2079336603146089992.post-6342695515957180962009-01-31T08:42:00.000-08:002009-01-31T09:33:56.081-08:00Did you get used to WebLogic?Last autumn it was quite a surprise for us when it turned out that after number of technical previews (four, actually) Oracle is giving up on OC4J and bringing BEA into its warm nest. Yeah, perhaps we should have listened better, or is it just me expecting that after TP1, TP2, TP3 and TP4 we get final release? Well, what's there is there. We had application in development which at some point took a turn from Jboss/Hibernate platform (it was quite a road, I tell you) and went Oracle style. In next series of posts we will describe in great detail what changing from on application server/persistence layer is like, and during last year we had two of them. Just when I was finishing the work on OC4J, big news of Weblogic coming to Oracle!<br /><br />I remember that last summer there was a poll on Oracle forum. Question was if we started developing products with TP4. At the time about 54% of people said yes, and twenty something said that they are going to. It is good thing I didn't start writing this blog back then :D After some time, I can say that we're cool with our new app. server. It is not like we had any choice, but Weblogic is quite good.<br /><br />Last few years I have been J2EE developer and I worked on Jboss and OC4J 10. So few words about them.<br /><br />Jboss is cool. I did not use it in production, just in development, but it was fast enough, it is cheapest you can get, nice community, configuring is XML based, but no restarts needed.<br /><br />OC4J 10. Well, at least it's got nce console... Not too nice, that default OC4J ADF look makes a man sick. Deployment was not flexible enough, speed, naah, and you needed to restart it quite more than you would like.<br /><br />OK, then the previews came. 1,2,3,4... We had no graphic console, but I can't say that making command scripts really hurts. If you want point-click, you are in wrong business. But bugs... Jesus, Joe and Marry! Weird errors, null pointer exceptions when you have unique constraints, totally useless error logging... Try developing on a thing like that. You hope for a finale release, remember the old days when everything was cool. OK, not everything was cool, but I least knew what was going on.<br /><br />So, what has Weblogic brought to us?<br /><br />First, my favourite topic, persistence layer. We got EclipseLink now! And I am really happy! All those cool stuff we had in TopLink is now here, it's in the community, we can see source (not that I need it, but it is good feeling ;) ) , guys on the news group respond to all our stupid and not so stupid questions in reasonable time. Using it is almost out of the box, since we need to put couple more lines in our persistence.xml to override using KODO (more about this in next post), we ran into couple of bugs (easy, easy...), but I am satisfied, mostly because you can get a lot uf useful info.<br /><br />I recomend this little site <a href="http://wiki.eclipse.org/EclipseLink">EclipseLink - Eclipsepedia</a> and a news group.<br /><br /><br />Then Weblogic itself. Nice console, a lot of options for deployment, strong base of users... No wonder Oracle bought it. Not so nice thing is that old BEA forum was not avalilable when I was looking for some answers, although it was shown in Google search results, so I had to use Google cache... JMS services are more complex than we got used to. All server is, actually, around clustering and guys that were presenting us Weblogic couple of months ago were proud of that.<br /><br />There are issues about compiling code (if you have generics), and structuring deployment archive. Adapting code that worked fine on Jboss and OC4J was not very pleasant thing, and the deployment archive we finally made work had quite unexpected structure. Now issues of transfering Oracle ADF security to a standalone production are main problem. We hope we will make it work... Just like everything else. I can only say for now that following instructions from Oracle site, was not enough.<br /><br />Actually, it was never enough. We had to experiment a lot, got couple of times in dead end, and sometimes I had exceptions that only occured two times on Google... And no one knew answer.<br /><br />I hope you had better luck. But we will be happy to share everythinig we found out so far. Maybe it will help someone (solidarity, brothers and sisters!) and perhaps some of you will have few pointers. On Monday I will start with basic persistence layer configuration and maybe few notes what doesn't work.<br /><br />Well, earn your daily bread with Weblogic! It is a good life.Miloš Stoiljkovićhttp://www.blogger.com/profile/03499273945104357217noreply@blogger.com0