Yazılım etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Yazılım etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

18 Temmuz 2018 Çarşamba

Injecting Template Example with Data Binding in Polymer 3.0

In the world of Web Components, it is always easy for a developer to set a property or attribute of a component but it is a little bit complicated to use a component inside another one with data binding for each.

If you are using Polymer Framework, the most obvious example is iron-list component. This component requires a <template> between its tags and each component in this template has its own data. An example is shown below:

<iron-list items="[[items]]">
  <template>
    <div> [[item.myProp]] </div>
  </template>
</iron-list>

Until Polymer 3.0, this was done with templatizing and slotting. I do not want to go into details but before Polymer 3.0, it was pretty much like below:

  • Polymer.Templatizer behavior should be added 
  • Main template of the component should be templatized : this.templatize(template)
  • Clone the item inside template tags with 
    • var clone = this.stamp()
  • Optionally, bind data you want inside this clone 
    • var clone = this.stamp({item:{"myProp":"Test"}})
  • And finally put your cloned element with data inside any HTML element
    • Polymer.dom(this.$.myDiv).appendChild(clone.root);
  • And that is it for < Polymer 3.0...

Things are a little different in Polymer 3.0. Again you should use the power of Templatize class but honestly it was very difficult to find a proper documentation or example to do this. So I want to share my experiences with you and I will do this with a real example. What I did is to create a simple custom-card component which has two properties firstText and secondText. This component is a simple card view which renders two given text with different colors. This is the easy one. My other component is a custom-list component which loops the first component in it with data binding by template injection.

<custom-list id="myList"> 
   <template>
      <custom-card first-text="Book Name: [[item.title]]" second-text="Author: [[item.author]]" />
   </template>
</custom-list>

Let's continue step by step:

1. You should import templatize class
import { templatize } from 'node_modules/@polymer/polymer/lib/utils/templatize.js';

2. Get the template object between tags of custom-list
var template = this.querySelector('template');

3. Call templatize method to get a TemplateClass object in order to do stamping
var TemplateClass = templatize(template);

4. Items property is an array contains JSON objects like {title:"MyItem", author:"MyAuthor"}. In a for loop, these object should be injected into each <custom-card> object as "item" property:
var instance = new TemplateClass( { item : this.items[i] } );
this.shadowRoot.appendChild(instance.root);

This simple code will let you iterate through each of your data in "items" property, create <custom-card> clones and inject this data into these clones. There is full working code available below. Hope this code block helps other developers who is struggling the same templatizing work in Polymer 3.0  

Code:


( polymer, polymer 3.0, template, templatizing, slot, inject, data bind, web components, stamp )

29 Aralık 2014 Pazartesi

Undefined reference to symbol 'v4l2_munmap' error while installing OpenCV 2.4.9 on Ubuntu 14.04

If you are dealing with image processing in one of your projects, almost all roads lead to OpenCV and Tesseract. Tesseract is a OCR library created by HP and currently is handled by Google. In order to get good results in OCR process, you need to preprocess your image for OCR. For this, you can use OpenCV image processing library. Maybe installing OpenCV in various platforms might be very easy but installing it on Ubuntu is a living hell.

There are plenty of guides and resources about installing OpenCV on Ubuntu. I tried most of them but every time I got the same error: " Undefined reference to symbol 'v4l2_munmap' ". Before installing OpenCV, some other packages must be installed on Ubuntu which you can find everywhere. If you install required packages and still got the same error, there is a solution.

Possibly, you get the error message below:

/usr/bin/ld: ../../lib/libopencv_highgui.a(cap_libv4l.cpp.o): undefined reference to symbol 'v4l2_munmap'
//usr/lib/x86_64-linux-gnu/libv4l2.so.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
make2: * [bin/opencv_test_highgui] Error 1
make1: [modules/highgui/CMakeFiles/opencv_test_highgui.dir/all] Error 2
make: ** [all] Error 2

To overcome this problem, all you need is to append " -lv4l2 " to [OPENCV_BUILD_DIR]/modules/highgui/CMakeFiles/opencv_test_highgui.dir/link.txt

After making the change, you need to execute make command again. Possibly, you will get the same error with different file names. All you need to do is applying same process to all files which gives the same error. For example if you see " modules/superres/CMakeFiles/opencv_test_superres.dir/all " near Error 2, you need to append " -lv4l2 " to [OPENCV_BUILD_DIR]/modules/superres/CMakeFiles/opencv_test_superres.dir/link.txt.

Unfortunately, you will get this error in more than 50 files. Of course more elegant solution is to detect these files and append " -lv4l2 " to all of them before starting make process.

By the way, if you want to compile OpenCV without bothering required packages or other things, there is a simple .sh file which handles all of these processes. You can download it from the link below and run the file to complete installation easily.


( opencv 2.4.9, tesseract, ubuntu 14.04, compile error, DSO missing from command line, -lv4l2 )
OpenCV installation script: https://github.com/jayrambhia/Install-OpenCV/tree/master/Ubuntu 
Reference: http://code.opencv.org/issues/3726

27 Kasım 2014 Perşembe

Custom TextView In Android With Styles

TextView is one of the most useful components in Android but at some point, it still cannot meet our requirements. For example, if you want to use a custom TypeFace (aka Font), you need to change it programmatically in the Activity like stated below:

Typeface typeFace = Typeface.createFromAsset(getAssets(), "Roboto-Regular.ttf");
TextView textView = (TextView) findViewById(R.id.myTextView);
textView.setTypeFace(typeFace);

Here, we've read our "Roboto-Regular.ttf" font file from "assets" folder and set it as the TypeFace of textView object. It is a good, simple, working solution but it is not feasible if you want to replace TypeFace for all of your TextViw components in the application. To set a custom font for all of your TextView components in your application, you can extend TextView class with your custom class. There are other methods like creating a custom component with its attributes using xml files but the solution below might be the best for you if you do not need too much feature but changing font family:

RobotoTextView.java
public class RobotoTextView extends TextView {
    public RobotoTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initialize();
    }
    public RobotoTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }
    public RobotoTextView(Context context) {
        super(context);
        initialize();
    }
    private void initialize() {
        if (!isInEditMode()) {
            Typeface currentTypeFace = getTypeface();
            int style = currentTypeFace.getStyle();
            Typeface type = setFontFamily(style);
            setTypeface(type);
        }
    }
    private Typeface setFontFamily(int style){
        Typeface type = null;
        if(style==Typeface.BOLD){
            type = Typeface.createFromAsset(getContext().getAssets(), "Roboto-Bold.ttf");
        }else if(style==Typeface.ITALIC){
            type = Typeface.createFromAsset(getContext().getAssets(), "Roboto-Italic.ttf");
        }else{
            type = Typeface.createFromAsset(getContext().getAssets(), "Roboto-Regular.ttf");
        }
        return type;
    }
    @Override
    public void setTypeface(Typeface tf, int style) {
        Typeface type = setFontFamily(style);
        super.setTypeface(type, style);
    }
}

MyView.xml
<com.test.RobotoTextView     android:id="@+id/myTextView"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text="My Custom TypeFace"
     android:textStyle="bold"/>

Here, I extend TextView class with my own custom class and override the necessary constructors with custom ones. One problem I faced during these processes was I cannot make the text bold, italic etc. To overcome this issue, you must find bold and italic versions of your font and put them in your assets folder also. Then you need to check the style attribute in your methods and retrieve the related .ttf file considering the style attribute (bold or italic). By doing this, you can easily use "android:textStyle" attribute in your custom TextView component.

( android, custom textview, typeface, style, bold, italic, andrpid:textStyle )

11 Mart 2014 Salı

ResourceBundle Usage In Maven

Recently, I've been working on converting standard web application projects to Maven web application projects in Netbeans. During this process, I've faced a problem. In standard java or java web projects, you can reach a properties file in every location inside the project. I mean if you put your properties file (eg. messages.properties) in a package like com.test.myproject.resources, you can reach that properties file with ResourceBundle like:

ResourceBundle rb = ResourceBundle.getBundle("com.test.myproject.resources.messages");

When you convert your projects to maven projects, you cannot access resources like this. Maven has a unique directory hierarchy to follow. When you create a Maven project, you will see a directory hierarchy like:

PROJECT_NAME > src > main > java - resources - webapp - ...

You can find the whole hierarchy in https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html

In this hierarchy, Maven forces you to put the related files to related folders. You should put web files to webapp folder, java files to java folder and resources to resource folder. If resource folder is not created automatically,  you can generate one. After that, messages.properties file should be put into resources folder. Then, you can reach your properties file by using ResourceBundle like:

ResourceBundle rb = ResourceBundle.getBundle("messages");

Maven sees resources folder as a root folder for resources so you do not need to specify and package name. You can successfully use your properties file in Maven.

( resourcebundle, maven, directory hierarchy, properties )

31 Ekim 2013 Perşembe

Primefaces Growl Not Rendered After Update

I continue forwarding my experiences on primefaces. Today I've had another issue and finally got the solution.

If you are using primefaces growl component to show messages after a process, you have to add a FacesMessage to FacesContext and update the component or set globalOnly attribute true. Ordinarily, growl must show up and show your test you put in FacesMessage. In my project, I push a primefaces command button that has an actionListener, I do things in server side, put my FacesMessage to the context and update my components in UI. But the growl does not show up. I've searched for the problem and finally say my mistake got the solution.

Here is my problematic code:
<h:form id="formNewF">

  <p:dialog widgetVar="dlgNewF" dynamic="true">
    <p:ajax event="close" listener="#{myController.closeF()}" update="formNewF"/>
    
    <p:panelGrid columns="3" id="newFPanel">
      <h:outputLabel for="fName" value="FName" /> 
      <p:inputText id="fName" value="#{myController.newF.name}" /> 
      <p:message id="fNameMessage" for="fName" display="text" />  
      <p:column/>
      <p:commandButton value="Save" update="newFPanel, dataTable" action="#{myController.saveF()}" oncomplete="if(!args.validationFailed){dlgNewF.hide();}"/> 
      <p:column/>
    </p:panelGrid>
  </p:dialog>

</h:form>

As you can see, I execute my saveF method. In that method, I put my FacesMessage to context. Here the problem comes. When I return to xhtml the code updates dataTable but the code in my oncomplete event triggers an ajax event which means that we have to go to the server side again. Remember, these are all happening before rendering the xhtml. So my second request to server side overrides the previous context or creates a new one and deletes my FacesMessage. This is the reason why growl does not render.

As a summary, more than one request to server side before rendering the view causes disappearing your FacesMessage and the growl does not render. You can solve this problem by removig the second request or doing the job in one server side request.

( primefaces, jsf, growl, facesmessage, facescontext, rendering, twice, not shown )

12 Eylül 2013 Perşembe

Primefaces Datatable Contextmenu Disappear Problem Fix

Updatable context menu is a big problem if you are using tree or datatable component of Primefaces. For example in my case, I have a datatable that has row which has different boolean flags. Depending of that flags, I have to change my context menu items. Basically, I have to render different context menus for each row in my datatable. First I tried to update context menu in element but there was a problem which I was finally able to solve...

ContextMenu component has two phases. One is generate or update phase and the other is show phase. If you try to update your context menu on right click, show phase comes first and then it updates itself. After this process, you will see that you context menu appears and disappears. While I was searching for a workaround, I found a post which helped me a lot in Primefaces forum. A guy found a solution which is overriding show function of context menu and then calling this method right after update process is done. This is the best solution I think. That guy applied this workaround for tree component. Below, you can find this approach that is applied to datatable.

<script type="text/javascript">
//patch to fix a problem that the context menu disappears after update
//delay the show to occure after the update 
var siteFunctions = {
    patchContextMenuShow: function() {
        var protShow = PrimeFaces.widget.ContextMenu.prototype.show;
        siteFunctions.patchContextMenuShow.lastEvent = null;
        PrimeFaces.widget.ContextMenu.prototype.show = function(e) {
            var ret;
            if (e) {
//saving last event
                siteFunctions.patchContextMenuShow.lastEvent = e;
                siteFunctions.patchContextMenuShow.lastEventArg = arguments;
                siteFunctions.patchContextMenuShow.lastEventContext = this;
            } else if (siteFunctions.patchContextMenuShow.lastEvent) {
//executing last event
                ret = protShow.apply(siteFunctions.patchContextMenuShow.lastEventContext, siteFunctions.patchContextMenuShow.lastEventArg);
//clearing last event
                siteFunctions.patchContextMenuShow.lastEvent = null;
            }
            return ret;
        };
    }
};

$(document).ready(function() {
    try {
        siteFunctions.patchContextMenuShow();
    } catch (e) {
        console.error(e);
    }
});
</script>

<p:contextmenu beforeshow="return true;" 
               for="dataTable" 
               id="contextMenuID" 
               widgetvar="tableContextMenuWV">
   <p:menuitem value="Menu 1" />
   <p:menuitem value="Menu 2" />
</p:contextmenu>
                
<p:datatable id="dataTable" widgetvar="dataTableW">
   <p:ajax event="contextMenu" 
           oncomplete="tableContextMenuWV.show();" 
           update=":formList:contextMenuID" />
</p:datatable>
( primefaces, jsf, datatable, row, context menu, update, show, disappear )
Kaynak : http://forum.primefaces.org/viewtopic.php?f=3&t=26813

31 Temmuz 2013 Çarşamba

Primefaces Row Toggle on Row Click

Due to the requests of people, I am going to write in English right now (for software topics).

Primefaces, which is a popular tag library for jsf has lots of different components which are pretty useful but these kid of libraries have some problems when you want to do something more detailed. I am going to help these people who are using Primefaces datatable component.

This component has a feature called rowToggler which let us toggle the row by clicking a generated triangle button. But what if you want to toggle the row by clicking anywhere on the row instead of just clicking rowTogglee button? The answer is below. I coded a little javascript stuff to make this feature work.

From one release to another, the css style names and html hierarchy may change in Primefaces. I make this code work in Primefaces v3.5.10. Putting code below to your xhtml page will make datatable rows expandable by clicking on the row:

<script type="text/javascript">
    $(document).on("click", ".ui-datatable-tablewrapper .ui-datatable-data tr.ui-widget-content", function() {
        /*1 - for expanded area*/
        if ($(this).hasClass('ui-expanded-row-content')) {
            return;
        }
        /*2 - to collapse open ones*/
        expandedRow = $('.ui-expanded-row');
        if (expandedRow.length !== 0 && !$(this).hasClass('ui-expanded-row')) {
            $('.ui-expanded-row-content').css('display', 'none');
            var untoggler = expandedRow.find('.ui-row-toggler');
            dataTableWidgetVarName.toggleExpansion(untoggler);
        }
        /*3 - for main expand feature*/
        var toggler = $(this).find('.ui-row-toggler');
        dataTableWidgetVarName.toggleExpansion(toggler);
    });

    $(document).on("click", ".ui-icon-circle-triangle-e", function() {
        if ($(this).hasClass('ui-icon-circle-triangle-s')) {
            return;
        }
        expandedRow = $('.ui-expanded-row');
        if (expandedRow.length !== 0) {
            $('.ui-expanded-row-content').css('display', 'none');
            var untoggler = expandedRow.find('.ui-row-toggler');
            dataTableWidgetVarName.toggleExpansion(untoggler);
        }
    });
</script>

First function is for the row and the second one is for the rowToggler button itself. Because of a bug in Primefaces, you cannot fire click event of the row when you click on images in the row. This is why I had to implement another click function for rowToggler button itself. You can find other descriptions below:

1 - This code block is for expanded area of the row. With this code, onthing happens when user clicks on expanded are of the row.

2 - This code brings a feature to close other expanded rows in datatable when user clicks another row.

3 - This is the main expand feature. When user clicks on the row, I am just calling toggleExpansion() function of datatable element.

Hope this post will help and guide someone who needs similar feature for datatable.

( primefaces, jsf, mojarra, datatable, row, rowToggle, toggleExpansion )

14 Mayıs 2013 Salı

JSF Ajax Requestlerdeki Tarayıcı Geri Butonu Sorunu ve Dojo İle Çözümü

Yine JSF kodlama ve yeni bir sorun ile karşı karşıyayız :) Aslında problem tam olarak JSF ile ilgili değil. Bir web uygulaması içerisinde AJAX request gönderildiğinde, URL üzerinde herhangi bir değişiklik olmuyor ise, tarayıcılar, hash değeri değişmediği için, içinde bulunduğu sayfayı tarayıcının History stack'ine eklemiyor. Dolayısıyla siz aynı sayfanın üzerinde bir çok işlem yapsanız bile, tarayıcıdaki sayfa adresi değişmediği için geri ve ileri butonlarını kullanamıyoruz.

Bu probleme çözümler mevcut aslında. Çoğu kişi tarayıcı geri-ileri butonlarını kullanıcıya kullandırtmak yerine uygulama içerisinde kendisinin oluşturduğu geri-ileri butonlarını javascript metodları vasıtasıyla kullandırtıyor. Fakat yine de tarayıcının butonlarına bir çözüm bulunmalı ve mevcut sürece entegre edilmeli. Bu noktada, araştırıp, biraz modifiye ederek uygulamamda kullandığım bir yöntemden bahsedeceğim.

Primefaces 3.5 ve JSF 2.1 kullanarak geliştirdiğim bir uygulamada, Primefaces Datatable elemanı içerisinde yüklü bir listem var ve bir file system dizini gibi, her bir satıra tıklandığında, o satırdaki klasörün içerisine girilmesi gerekiyor. Geri ve ileri butonlarının da çalışması gerekiyor.

Bu noktada çözüm olarak dojo'nun back sınıfını kullandım. Bu kütüphane, her bir click eventi esnasında, history stack'ine bir veri kaydetmemizi sağlıyor. Bu veriyi de, geri ve ileri butonlarına tıklandığı zaman yapacağı işlemi tanımlayarak kaydediyoruz. Böylece kullanıcı geri butonuna bastığı zaman, kaydettiği parametrelerle işlem yapabiliyor.

Kodlarla özetlemek gerekirse:

myfiles.xhtml
<script>
     function HistoryState(fileid)
     {
           this.fileid = fileid;
           this.back = function() { 
                browserBck([{name: 'fileid', value: fileid}]);
           };
           this.forward = function() { 
               browserFrwrd([{name: 'fileid', value: fileid}]);
           };
           this.changeUrl = false;
       }
</script>

<script type="text/javascript"  src="js/dojo.js" djConfig="preventBackButtonFix: false"></script>
<script type="text/javascript">
     dojo.require("dojo.back");
     dojo.back.init();
     dojo.back.setInitialState(new HistoryState(null));
</script>

...<p:dataTable>... 
        <p:ajax event="rowSelect" listener="#{fileController.list()}"/> 
...</p:dataTable>

   <p:remoteCommand name="browserBck" action="{fileController.listBack()}"/> 

Yukarıdaki örnekte HistoryState adında bir nesne oluşturdum. Bu nesnede, dojo için gerekli olan back, forward ve changeUrl değişkenlerini set ettim. back değişkeni, geri butonuna tıklanınca yapılacakları, forward değişkeni ileri butonu için aynı işlemleri tanımlamamızı sağlıyor. changeUrl ise, her bir state kaydolurken dojo tarafından oluşturulan random rakamın adres satırına yazılıp yazılmamasını kontrol ediyor. HTML5 desteği olmayan tarayıcılar için bu değer true olmalı. Sayfa ilk defa render olurken ise setInitialState'i çalıştırıp işlemi başlatıyoruz. Yine aynı dosyada bulunan p:dataTable elemanının bir satırına tıklanınca server tarafında liste yenilemek için <p:ajax> kullandım:

FileController.java
public void list() {
        RequestContext rc = RequestContext.getCurrentInstance();
        rc.execute("dojo.back.addToHistory(new HistoryState('" + selectedFile.getId() + "'));");
        listByParentID(selectedFile.getId());
}

public void listBack() {
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); 
        String fileID = ec.getRequestParameterMap().get("fileid");
        listByParentID(fileID);
} 

Yukarıdaki örnekte görüldüğü gibi, her bir listeleme işleminde, client tarafındaki addToHistory metoduna, HistoryState nesnemi ,içerisinde mevcut parent id bulunacak şekilde set ediyorum.

Bu örnek çok daha basitleştirilbilirdi fakat JSF ve server side'da detaylı bir örnek bulunsun istedim.

Süreci Özetlersek:
1 - xhtml dosyasında dojo'yu initialize ettik. History'ye kaydedeceğimiz nesneyi ve back-forwad metodlarımızı belirledik
2 - Bir linke tıklayıp server tarafına bir ajax request geçtik. Server tarafındaki metodda "RequestContext.getCurrentInstance().execute()" ile client tarafındaki dojo.back.addHistory metodunu çağırdık.
3 - Tarayıcının geri butonuna bastık. Bu işlem, 1. maddede belirlediğimiz back metodunu çağırdı (client-side).
4 - <p:remoteCommand> ile, 3. maddede çağrılan metodun, server tarafındaki başka bir metodu çağırmasını sağladık.
5 - Server tarafındaki metod ise istediğimiz listelemeyi yaptı ve geri butonumuz çalışmış oldu.

İleri butonu için de, forward nesnesine gerekli fonksiyonu tanımlayarak aynı işlemleri tekrarlamamız lazım.

Not: Bu şekilde çalışabilmesi için 'js' klasörünün içerisinde;
* dojo.js
* back.js
* resources/iframe_history.html

dosyalarının bulunması gerekiyor.

( jsf, primefaces, ajax, browser back button, forward, dojo, dojo.back, dojo.hash, request, xhtml, p:remoteCommand, p:dataTable )
Kaynak: http://blog.andreaskahler.com/2009/09/managing-browser-history-for-ajax-apps.html

7 Mayıs 2013 Salı

JSF ve HTML Escape Problemi, Çözümü

JSF teknolojisi, web uygulamaları geliştirirken standart olarak yazılımcının uygulaması gereken bir çok güvenlik açığını kendisi gidermektedir. Bunların en önemlilerinden birisi de XSS'i engellemek için render edilen HTML'de bulunan ve atak yapmaya müsait karakterleri escape etmesidir. Örneğin ">" şeklinde yazılan bir yazı, kaynak kodunda "&gt;" şeklinde gözükecektir. Bu özellik güvenlik açısından kolaylık sağlasa da bir takım kısıtlamalar da getirmektedir. Örneğin, yazılımcının kendisinin, xhtml içerisine yazacağı javascript ya da benzeri kod blokları, JSF'in bu özelliği sebebi ile ya compile olmaz, ya da ekranda sorunlu bir şekilde render edilir.

Bu problemin çözümü ise <h:outputText> kullanmaktır. Bu tag ile, JSF'in default davranışını bypass edebiliriz. Örneğin basit bir Javascript tagi kullanalım:
<script>alert('Test');</script>
Bu kod bloğunu direkt olarak xhtml içerisine yazarsak &lt;script&gt;alert('Test');&lt;/script&gt; gibi bir görüntü ile karşılaşırız ya da IDE'miz bu kodu derlemez, hata verir. Bu kodu önyüze taşımak için:
<h:outputText value="&lt;script&gt;alert('Test');&lt;/script&gt;" escape="false" />
şeklinde bir kullanımda bulunmalıyız. Burada, h:outputText içerisindeki değerin escape="false" ile escape edilmemesini sağlıyoruz. Burada value'yu bu şekilde vermek yerine normal bir şekilde yazarak bir String halinde tutup: <h:outputText value="#{fooController.myScript}" escape="false" /> şeklinde de kullanabilirsiniz.

Görüldüğü üzere yöntem oldukça basit. Fakat benim başıma gelen bir problem, bu şekilde bir çözüme gitmeyi engelledi ne yazık ki. Sorun şu şekilde; Internet Explorer versiyonlarına göre farklı CSS dosyaları kullanmak için html taginin başına:
"<!--[if lt IE 7]> <html lang=\"en-us\" class=\"no-js ie6\" xmlns:h="http://java.sun.com/jsf/html"> <![endif]-->..." 
tarzı kodlar yazarız. Bu kodları, yukarıda bahsettiğim şekilde escape etmek ne yazık ki mümkün değil çünkü kullandığımız <h:outputText>'in dahil olduğu "http://java.sun.com/jsf/html" namespace'ini, henüz tanımlamadan bu tagi kullanmak istiyoruz ki bu da mümkün değil. Burada da imdadımıza <f:view> tagi geliyor. <f:view> taginin içerisine namespace'lerimizi tanımladıktan sonra bütün içeriğimizi (<html> tagi vs. de dahil), <f:view> içerisine koyuyoruz. Böylece içeride <h:outputText>'i kullanabilir duruma geliyoruz ve sorunumuz çözülmüş oluyor. Daha anlaşılır olması için:

Sorun: Aşağıdaki kod bloğunu escape etmeden ön tarafa taşımak
<!--[if lt IE 7]>          <html lang="en-us" class="no-js ie6"> <![endif]-->
<!--[if IE 7]>             <html lang="en-us" class="no-js ie7"> <![endif]-->
<!--[if IE 8]>             <html lang="en-us" class="no-js ie8"> <![endif]-->
<!--[if gt IE 8]><!--> <html lang="en-us" class="no-js" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <!--<![endif]-->
Çözüm: Kod bloğunu <f:view> içerisine alıp namespace'leri buraya taşımak
@Controller("fooController")
FooController{
   public String myUnescapedString =
 
                    "<!--[if lt IE 7]><html lang=\"en-us\" class=\"no-js ie6\"> <![endif]-->\n" +
                    "<!--[if IE 7]><html lang=\"en-us\" class=\"no-js ie7\"> <![endif]-->\n" +
                    "<!--[if IE 8]><html lang=\"en-us\" class=\"no-js ie8\"> <![endif]-->\n" +
                    "<!--[if gt IE 8]><!--> <html lang=\"en-us\" class=\"no-js\"> <!--<![endif]-->";
}
<f:view contentType="text/html"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core">
<h:outputText value="#{fooController.myUnescapedString}" escape="false"/>
</f:view>
( jsf, html, escape, h:outputText, f:view, unescape, xss )
Kaynak: http://stackoverflow.com/questions/10616944/jsf-2-1-ie-conditional-comments

7 Mart 2013 Perşembe

Ubuntu 12.10'a Oracle SQL Developer Kurulumu

Bu kurulum için ihtiyacımız olan bir kaç kurulum daha var. Öncelikle sistemde jre'nin kurulu olması gerekiyor. debhelper ve sqldeveloper-package paketlerine de ihtiyacımız var. Tabiki bir de ziplenmiş olarak indirdiğiniz SQL Developer'a ihtiyaç var.  Bu yazıda ben 'sqldeveloper64-3.2.20.09.87-no-jre.zip' kullanıyor olacağım.

sudo apt-get install sqldeveloper-package debhelper

Bu kodu çalıştırıp gerekli paketleri kurduktan sonra aşağıdaki komutla .deb dosyasını oluşturuyoruz:

make-sqldeveloper-package sqldeveloper64-3.2.20.09.87-no-jre.zip

Bu esnada make-sqldeveloper-package paketinde bulunan bir bugdan ötürü chmod: missing operand after `755' hatası alabilirsiniz. Bu hatayı çözmek için bu paketin kodunda ufak bir değişiklik yapmamız gerekiyor. Paketin versiyonuna göer değişiyor fakat 370 ile 385. satırlar arasında bir yerlerde bulunan aşağıdaki kodu, bir alttakiyle değiştirmeniz gerekiyor:

Silinecek Satır
${FIND} "${OPTDIR}" ! \( -type d -o -name "*.jar" \) |${XARGS} ${XARGS_OPTS} ${FILE} ${FILE_OPTS} |${GREP} ${GREP_OPTS} "shell script text executable" |${CUT} ${CUT_OPTS_FUNC_CLEAN} |${XARGS} ${XARGS_OPTS} ${CHMOD} ${CHMOD_OPTS}

Yerine Eklenecek Satır
${FIND} "${OPTDIR}" ! \( -type d -o -name "*.jar" \) |${XARGS} ${XARGS_OPTS} ${FILE} ${FILE_OPTS} |${GREP} ${GREP_OPTS} "shell script" | ${GREP} ${GREP_OPTS} "text executable" |${CUT} ${CUT_OPTS_FUNC_CLEAN} |${XARGS} ${XARGS_OPTS} ${CHMOD} ${CHMOD_OPTS}

Bu işlemden sonra hatadan kurtulmuş oluyoruz ve kodu yeniden çalıştırdığımızda .deb uzantılı dosyamız oluşmuş oluyor. Aşağıdaki şekilde .deb paketini açıyoruz:

sudo dpkg -i sqldeveloper.......deb

Böylece kurulum tamamlanmış oluyor. Dash Home'a "sqldeveloper" yazdıktan sonra uygulamamız açılacak. Yalnız yapmamız gereken son bir işlem daha var. Uygulama ilk kez açılırken size yüklü olan JRE'nin lokasyonunu soracak. Buraya da yüklediğimiz JRE'nin lokasyonunu yazacağız. Örneğin benimki şu şekildeydi:

/usr/lib/jvm/java-7-oracle

Artık IDE'miz kullanıma hazır durumdadır.

( ubuntu 12.04, oracle, sql developer, chmod, 755 )
Kaynak : https://bugs.launchpad.net/ubuntu/+source/sqldeveloper-package/+bug/985810

1 Mart 2013 Cuma

Spring MVC @Autowired NullPointerException

Spring MVC'de, nesnelerin yönetimini framework'e bırakma olayı sıkça kullanılan bir durumdur ve Spring'in ana kullanım amaçlarından birisidir. Bu kullanımlar esnasında, @Autowired annotation'unu kullanarak ya da getBean() metodu ile nesnelere ulaşmak istediğimizde alınan NullPointerException da oldukça sık karşılaşılan bir durumdur:) Ben yazının geri kalanında Annotation kullanımı ile devam edeceğim.

Burada, hataya sebebiyet verecek milyonlarca ihtimal vardır. Internette araştırdığınızda da bir dolu yazı karşınıza çıkacaktır. Bu sebeplerden bir kaçı:

  • @Autowired kulllandığınız nesneye sahip sınıfın Spring tarafından inject edilmemiş olması. Yani bu nesneye ait sınıfın başında @Component, @Controller gibi Spring'e özgü ve o sınıfın Spring tarafından yönetildiğini belirten annotationlar kullanılmalıdır.
  • Annotation kullanılan durumlarda, springContext.xml içerisinde '<tx:annotation-driven />' ve '<context:component-scan base-package />' taglerinin kullanılması gerekir.
  • Başına @Autowired eklediğiniz bir nesneyi 'new MyClass()' şeklinde kendiniz oluşturmamalısınız; bu nesnenin yönetimi artık Spring'dedir.

Yukarıdaki maddelere eklenecek başka maddeler de vardır. Bu hatalardan bir ya da birkaçına düştüyseniz kullanmak istediğiniz nesnenin null olması ihtimal dahilindedir. Peki herşeyi denediniz, bütün kodlama doğru ve hala bu hatayı alıyorsanız? O zaman benim karşılaştığım durumla karşılaşmış olma ihtimaliniz var. Spring MVC, kontrolüne verdiğiniz sınıfın instance'ını oluştururken, constructor'ı çalıştırma esnasında autowired nesneyi henüz inject etmiyor. Dolayısıyla bu nesneyi consturctor içerisinde kullanıyorsanız NullPointerException alıyorsunuz. Bu sorunun çözümü ise, eğer sınıfın instance'ını oluştururken yapmanız gereken bir iş yok ise, constructor içerisindeki bütün kod bloğunu @PostConstruct annotation'una sahip bir metoda vermeniz. Böylece ilgili nesne Spring tarafından oluşturulmuş ve kullanıma hazır hale gelmiş olacaktır. Aşağıda örnek kod parçalarını bulabilirsiniz.

Yanlış Kullanım

@Controller("userController")
public class UserController implements Serializable{
    @Autowired
    transient private SessionController sessionController;
    
    public UserController() {
        System.out.println(sessionController.getActiveUser().getUserName());
    }
}

Doğru Kullanım

@Controller("userController")
public class UserController implements Serializable{
    @Autowired
    transient private SessionController sessionController;
    
    public UserController() {}
    
    @PostConstruct
    public onLoad() {
        System.out.println(sessionController.getActiveUser().getUserName());
    }
}

spring mvc, injection, autowiring, @autowired, nullpointerexception, constructor, postconstruct )

20 Şubat 2013 Çarşamba

Spring Security Invalid Session Ajax Redirect Sorunu

Merhaba,

Bu aralar sıkça uğraştığım Spring Security hakkında yazdığım yazılara devam ediyorum. Bu seferki problem invalid hale gelmiş bir sessionda ajax request gönderdiğimizde view kısmında herhangi bir aksiyon olmaması. Önce problemin kaynağını belirteyim. Giden standart bir request'in response'ı ekrada düzgün bir şekilde gösterilirken giden bir ajax requestin response'ı partial-response olmalıdır. Uygulamada herhangi bir sayfadayken session timeout gerçekleştiğinde ve biz sonrasında ajax request gönderen bir işlem yaptığımızda spring security'nin standart jsf redirection metodu ajax response'ı redirect edemiyor. Bu noktada yapmamız gereken custom bir RedirectStrategy yazmak. Bu sınıf InvalidSessionStrategy sınıfını implement etmeli ve onInvalidSessionDetected metodunda ajax requesti yakalayıp ona göre farklı bir işlem yapmalıyız. İsterseniz burada http error gönderebilirsiniz. Ben bunun yerine bir partial response yazdım ve redirect işlemi gerçekleştirdim.

İhtiyacınız olacak örnek sınıf ve konfigürasyonları aşağıda bulabilirsiniz.

spring-security.xml
...
<http>
   <custom-filter ref="sessionManagementFilter" before="SESSION_MANAGEMENT_FILTER" />
</http>
<beans:bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter">
   <beans:constructor-arg name="securityContextRepository" ref="httpSessionSecurityContextRepository" />
   <beans:property name="invalidSessionStrategy" ref="customRedirectStrategy" />
</beans:bean>
<beans:bean id="customRedirectStrategy" class="com.test.JsfRedirectStrategy"/>
<beans:bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/>
...

JsfRedirectStrategy.java
...
implements InvalidSessionStrategy
...
    @Override
    public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response){
        String redirectUrl = "invalid-session.xhtml";
        boolean ajaxRedirect = isAjaxRequest(request);
        if (ajaxRedirect) {
            if (request.getSession() != null) {
                HttpSessionRequestCache httpSessionRequestCache = new HttpSessionRequestCache();
                SavedRequest savedRequest = httpSessionRequestCache.getRequest(request, response);
                if (savedRequest != null) {
                    httpSessionRequestCache.removeRequest(request, response);
                }
            }
            String ajaxRedirectXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><partial-response><redirect url=\"" + redirectUrl + "\"></redirect></partial-response>";
            response.setContentType("text/xml");
            PrintWriter out = response.getWriter();
           out.write(ajaxRedirectXml);
           out.flush();
           out.close();
        } else {
            response.sendRedirect(redirectUrl);
        }
    }

Yukarıda mavi renkli kod bloğunu sebebi ise AJAX targetURL'i silmek. Yoksa bir sonraki tıklamada ekrana kaydedilmiş AJAX requesti basılıyor. Eski Spring Security versiyonlarında direkt olarak URL'i de silebiliyorduk fakat 3.1.3 versiyonunda ben SavedRequest'i silerek bu işlemi gerçekleştirdim.

Bir diğer önemli konu ise, yukarıdaki işlemi ben yalnızca session invalidate olurkenki süreçte gerçekleştirdim. Bir de daha önce invalide olmuş bir session varken gönderilen bir AJAX request olması durumu olabilir (Örneğin yeni bir sekmede uygulamaya devam ediyorsunuz, logout yapıp sessionu öldürdünüz fakat bir önceki sekmede bulunan açık olan sayfada ajax request gönderen bir linke tıkladınız). Bu tarz bir durumda ise AuthenticationEntryPoint sınıfını implement edip commence metodunu aynı şekilde oluşturmalısınız. Bu yöntemle, hiç bir requesti kaçırmayıp, kullanıcıyı istediğiniz adrese yönlendirebilirsiniz.

Bir üstteki paragrafa örnek sınıf:

CustomAuthenticationEntryPoint.java
...
implements AuthenticationEntryPoint
...
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
        //Bir önceki sınıftaki kodun aynısı
    }

spring mvc, spring security, session management, invalid session, ajax redirect, jsf, redirect strategy, invalid session strategy )
Kaynak: http://code.google.com/a/apache-extras.org/p/ajax4click/wiki/ConfiguringSpringSecuritySessionTimeout
Kaynak: http://www.icesoft.org/wiki/display/ICE/Spring+Security

18 Şubat 2013 Pazartesi

Spring Security Session Management Concurrency Control Problemi

Springde session yönetimini Spring Security ile yapmak isteyenler, eş zamanlı session yönetimini de basit bir şekilde spring-security.xml dosyasını değiştirerek yapabilirler. Bu noktada, gerekli düzenlemeleri yaptıktan sonra bile aynı bilgiler ile login olan kullanıcı, session oluşturamaması gerekirken bu işlemi yapabiliyorsa, çok büyük ihtimalle UserDetails sınıfınızdaki bir problem ile karşı karşıyasınız.

Buradaki sıkıntı, Spring Security'yi kullanabilmek için gerekli olan default kullanıcı arayüzü olan UserDetails'in implement edilmesi esnasında yaşanıyor. Bu arayüzü implement ederken oluşturduğumuz  kendi kullanıcı sınıfımızda equals metodunu override etmemiz lazım. Çünkü bu metod içerisinde, sessionu oluşturan kullanıcıların concurrent olup olmadığını anlamamız için belirleyeceğimiz bir ya da birden fazla alanın karşılaştırılıp aynı olup olmadığının kontrol edilmesi gerekiyor. Bu metodu override ettikten sonra belirlediğimiz aynı alana sahip başka bir kullanıcı session oluşturmaya çalışınca Authentication hatası alacaktır.

Örnek vermek gerekirse;

Bir adet User sınıfımız olsun. Uygulamamızda bir kullanıcı session oluşturmuşken aynı kullanıcı adına sahip başka bir kullanıcının session oluşturmamasını istiyoruz. Örnek dosyalar aşağıdaki gibi olmalıdır:

web.xml
...
<listener>
  <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
...

spring-security.xml
...
<session-management invalid-session-url="/no-sess.xhtml">
  <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/no-sess.xhtml" />
</session-management>
...

MyUser.java
public class MyUser implements UserDetails
...
   @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyUser other = (MyUser) obj;
if (userName == null) {
if (other.userName != null)
return false;
} else if (!userName.equals(other.userName))
return false;
return true;
  }
...

Bu konfigürasyonlar sonrasında bir kullanıcı session oluşturmuşken aynı kullanıcı adı ile başka bir session oluşturmaya çalışırsanız 'Maximum sessions of 1 for this principal exceeded' gibi bir hata mesajı alacaksınız.

spring mvc, spring security, session management, concurrency control, max-sessions, UserDetails )

21 Aralık 2012 Cuma

HttpURLConnection İle Web Sayfası İçeriği Almak

Java'da basit bir şekilde ve herhangi bir ekstra kütüphane kullanmadan HTTPURLConnection sınıfı ile bir web sitesine bağlanıp içeriğini almak konusunda ufak bir kod parçası ile örnek vereceğim. Bu işlemi, bir web sayfasını tamamen String olarak çekip parse etmek ya da GET, POST vs. ile çalışan bir REST servisi çağırmak için kullanabilirsiniz.

Aşağıdaki örnekte http://www.mehmetaktas.org?param1=VALUE1&param2=VALUE2 şeklinde bir adresin içeriğini çekeceğiz.

public String getURLContent(){
        String uri = "http://www.mehmetaktas.org?param1=value1&param2=value2";
        HttpURLConnection connection = null;        
        
        try {
            
            //Bağlantımızı açıyoruz
            URL url = new URL(uri);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");//POST, PUT, DELETE ...
            connection.setUseCaches(false);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            /*
             * Content-Type, Content-Language gibi request property set etmek
             * istersek aşağıdaki metod kullanılabilir:
             * connection.setRequestProperty("Content-Language", "tr-TR");
             */
            //Response'ı alıyoruz
            InputStream is = connection.getInputStream();
            BufferedReader rd = new BufferedReader(new InputStreamReader(is));
            String line;
            StringBuilder response = new StringBuilder();            
            while ((line = rd.readLine()) != null) {
                response.append(line);
                response.append('\r');
            }
            rd.close();
            is.close();
            
           return response.toString();
            
        } 
        catch (Exception e) {} 
        finally {
            if (connection != null) {
                connection.disconnect();                
            }
        }
    } 

httpurlconnection, screenscraper, java, url, connection, web page, parse, rest, get, post )

13 Aralık 2012 Perşembe

Operation Not Allowed After ResultSet Closed

Merhaba,

JDBC kullanarak Java'da veritabanı bağlantısı yapıp veri çekmeye çalışırken "rs.next()"ile bir veriye ulaşırız. Bu metodu çağırdığımız esnada "java.sql.SQLException: Operation not allowed after ResultSet closed" şeklinde bir taha alıyorsanız olası bir kaç sebebi var. Bu sebeplerin başında ResultSet nesnenizi kullanırken bir döngü ya da başka bir metodun içerisinde "rs.close()" metodunu kullanarak ya da nesneyi null yaparak hata alma durumunuz vardır. Bu problemi, biraz araştırarak çözebilirsiniz fakat "Ben ResultSet nesnemi kesinlikle kapatmıyorum ya da null yapmıyorum neden böyle oluyor?" derseniz sebebi bulmak biraz zor olabilir. Böyle bir durum başıma geldi ve çözümünden bahsedeceğim.

Java tarafında veritabanına bağlanırken ResultSet nesnesini doldurmak için bir Statement ya da PreparedStatement nesnesi kullanırız. Bu nesne teoride bir adet ResultSet'e hizmet verebilir. Statement kapandığı zaman, ona bağlı olan ResultSet de kapanır. Sıkıntı da aslında buradan kaynaklanıyor. Özellikle uzun sürede sonuç getiren bir sorgu çalıştırdığınız zaman Statement, uygulama sunucusunun pool ayarlarında tanımlı olan Statement Timeout'una takılıyor. Bu esnada Statement, uygulama sunucusu tarafından kapatıldığı için ResultSet nesnesi de kapanmış oluyor. Siz de herhangi bir veri çekmeye çalıştığınızda en tepede bahsettiğim hatayı alıyorsunuz.

Bu sorunu, SQL sorgunuzu optimize ederek ya da uygulama sunucusundaki kullandığınız veritabanı pool'unun Statement Timeout süresini uzatarak çözebilirsiniz. Glassfish için bu ayara "Resources > JDBC > JDBC Connection Pools > POOL_ADI > Advanced" menüsünden ulaşabilirsiniz.

java, jdbc, statement, resultset, pool, timeout, sqlexception, connection )

12 Aralık 2012 Çarşamba

Aspx Html Çift Title Sorunu

Aspx kullanarak oluşturulan web sitelerinde işimiz yarayan MasterPage'den kaynaklı olarak bir duplicate <title> tag problemi yaşıyor olabilirsiniz. Bunun başlıca sebebi, master sayfasının <head> tagleri arasında bulunan ContentPlaceHolder aslında. Her bir sayfada farklı bir title kullanmak istediğimizde <title>Sayfa Bilgisi</title> kodunu master sayfadaki <head> tagi arasına koymak yerine master sayfasındaki <head> tagi içerisine bir adet ContentPlaceHolder atarız. Sonrasında oluşturduğumuz sayfada bu ContentPlaceHolder'ın içeriğini koyacağımız yere <title> tagimizi koyarız. Bu işlem, sayfa render edildiğinde biri boş olmak üzere iki adet <title> tagine sebep olmaktadır. Bunun sebebi, server tarafında çalışan ve <head> içerisinde bulunan ContentPlaceHolder'ın, <title> tagini bulamayıp kendisinin ekstra bir adet daha üretmesidir.

Sorunun çözümü ise basit. Title bilgisini <title> tagi arasına koymak yerine sayfanın en tepesindeki <%@ Page Title=""... içerisine koymak. Sırasıyla sorunlu kod ve düzeltilmiş kod aşağıdaki gibi olmalıdır.

Hatalı Kod:
<%@ Page Title="" Language="C#" MasterPageFile="~/Mstr.master" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
    <title>BASLIK</title>
     ...
</asp:Content>


Doğru Kod:
<%@ Page Title="BASLIK" Language="C#" MasterPageFile="~/Mstr.master" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
    ...
</asp:Content>

( aspx, .net, <title>, <head>, çift title, contentplaceholder, masterpage, content, runat="server" )



6 Kasım 2012 Salı

Java İle Basit Tek Taraflı Şifreli Metin Üretme

Özellikle veritabanında tutulmaması gereken veriler olduğunda ya da network üzerinde açık olarak gitmesini istemediğimiz veriler olduğu durumlarda tek taraflı olarak verileri şifreleriz. Örneğin girilen bir şifrenin doğru olup olmadığını kontrol ederken veritabanındaki şifrelenmiş metin ile kullanıcıdan gelen açık metini şifreleyerek karşılaştırırız. Böylece kullanıcının şifresini bilmeden şifresini doğrulayabiliriz. Bunun için kullanılabilecek en basit yöntemi aşağıda göstereceğim.
import java.security.MessageDigest;
import sun.misc.BASE64Encoder;
public final class Sifre {
     public static String sifrele(String mesaj,String algoritma, String encoding){
          MessageDigest md = null;
          String hash = null;
          try {
               md = MessageDigest.getInstance(algoritma);
               md.update(mesaj.getBytes(encoding));
               md.update("TUZ".getBytes(encoding));
               byte rawByte[] = md.digest();
               hash = (new BASE64Encoder()).encode(rawByte);
          } catch (Exception e) {
          }
           return hash;
     }

     public static void main(String args[]) throws Exception {
          String sifre = "PASSWORD";
          System.out.println(sifrele(sifre, "SHA", "UTF-8"));
          System.out.println(sifrele(sifre, "MD5", "UTF-8"));
     }
}
( java, hash, password, encrypt, salt, sha, md5 )

19 Ekim 2012 Cuma

Glassfish'de Request URI Is Too Large Hatası

Glassfish uygulama sunucuna yüklenmiş bir web uygulamasındaki servlet'e GET ya da POST ile gitmeye çalıştığınızda Request URI is too large. java.nio.BufferOverflowException gibi bir hata almanız olası. Böyle bir durumda sıkıntı aslında TCP ile ilgili yani networksel bir problem. Yaşamadım fakat tahminimce Glassfish üzerine herhangi bir byük boyutlu uygulama yüklerken de benzer bir hata ile karşılabilirsiniz. Bu noktada yapılması gereken ise Glassfish'in network ayarlarındaki buffersize'ı artırmak olacak.

4848 portundan (default) Glassfish'in admin arayüzünü açıyoruz. Sonrasında sol taraftaki menüden sırasıyla: Configurations > Server-Config > Network Config > Transports > Tcp 'ye tıklayarak TCP menüsünü açıyoruz. Buradaki buffer size kısmını ihtiyacımız olduğu ölçüde artırıp uygulama sunucusuna restart attığımızda aynı problem ile karşılaşmayacağız.

( glassfish, tcp, buffer size, request uri too large, servlet, get, post ) 

16 Ağustos 2012 Perşembe

Servlet Web Service Endpoint '' Failure

Java ile web servis geliştirirken basit tipleri ve sınıfları kullanırken çok fazla problem yaşanmaz fakat kendi oluşurduğumuz sınıfları kullanmak istersek bir takım sorunlar yaşayabiliyoruz. Karşılaştığım  ve sebebini gerçekten çok zor bulabildiğim bir problemin çözümünden bahsedeceğim şimdi.

JAX-WS web servis oluştururken, daha önce başka bir projemde oluşturduğum bir sınıfı web servis metodunun dönüş nesnesi olarak belirledim. Fakat bu metodu yazıp projeyi derlemeye ya da çalıştırmaya çalıştığımda aşağıdaki hatayı aldım:

Error occurred during deployment: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: java.lang.RuntimeException: Servlet web service endpoint '' failure. Please see server.log for more details.
/.../nbproject/build-impl.xml:725: The module has not been deployed.
See the server log for details.

Hata da çok fazla bir detay yok, derinlemesine koda girmem gerekti. Söylediğim gibi web servisler xml tabanlı olduğu için uğraştığınız sınıflarda herşeyin tanımlı olması lazım. Benim metodumda dönen sınıfın default constructor'ı tanımlanmamıştı. Bunu fark ettiğimde hemen bir cosntructor tanımlayıp denedim ve web servisin çalıştığını gördüm. Yani sorun, dönmek istediğim sınıfta default constructor olmamasıydı. Benim sınıfımda public olan başka hiç constructor yoktu dolayısıyla belki parametreli public constructor tanımlayarak da aynı şekilde çözüme gidilebilir.

( java, web servis, jax-ws, default constructor, illegalstateexception, lifecycleexception, endpoint, build-impl.xml )

23 Temmuz 2012 Pazartesi

android.database.sqlite.SQLiteMisuseException: error code 21

Merhaba,

Android tarafında karşılaştığım bir sorunu ve kısmi çözümünden bahsetmek istiyorum. Geliştirdiğim uygulamanın bir bölümünde SQLite bağlantısı yapıp veritabanına bir veri insert etmem gerekti. Bunu yaparken ilk önce SQLiteStatement kullanım parametreleri bind ederek kullanmak istedim. Bu şekilde parametreleri set edip executeInsert() metodunu çağırdığımda:
java.lang.RuntimeException: Unable to start activity ComponentInfo: android.database.sqlite.SQLiteMisuseException: error code 21: not an error
Şeklinde bir hata ile karşılaştım. Biraz araştırma yaptığımda öncelikle kaynaklarda, bu hatanın, birden çok threadin aynı anda veritabanı bağlantısı açıp kapaması esnasında olabildiğinden bahsediliyordu. Benim kodumda threadli bir yapı olmadığı gibi benzer bir kullanım da yoktu. Bu nedenle sorun bundan kaynaklı değildi. Sonrasında bir forumda başka bir arkadaş sorunun cihazın Türkçe set edilmiş Locale ayarlarından kaynaklı olabileceğini söylemişti. Bunu denemeye karar verdim. Cihazı İngilizceye çevirdiğim zaman sorun ortadan kalktı. Fakat kod tarafında bir şekilde Locale set ederek bu hatadan kurtulunmuyordu. Sonrasında kendi çözümümü ürettim. Belki bu soruna direkt olarak bir çözüm değil fakat benzer problemle karşılaşan arkadaşlar SQLiteStatement kullanmak yerine SQLiteDatabase sınıfının insert() metodunu kullanırlarsa bu sorunu çözebilirler. Tabi ki burada parametreleri artık ContentValues ile set etmek gerekecek. İlk başta belirttiğim gibi bu nedenle bu çözüm kısmi bir çözüm ama en azından hatadan kurtulabilirsiniz. 

Merak eden arkadaşlar için, hatayı aldığım cihazın gerekli bilgileri şu şekildedir:
Samsung Galaxy TabAndroid 3.2, Türkçe Locale  
( android, honeycomb, 3.2, sqlitemisuseexception, error code 21: not an error, sqlitedatabase, sqlitestatement, contentvalues )
Kaynak: http://stackoverflow.com/questions/9685633/sqlitemisuseexception-error-code-21-when-inserting-a-row