[Java] Reverse iteration

Java 2016.04.29 10:02

Java의 List 를 iteration 할때 역순으로 탐색하고 싶은경우 ListIterator 를 다음과 같이 사용하면 된다.

for (ListIterator iterator = list.listIterator(list.size()); iterator.hasPrevious();) {
  final Object listElement = iterator.previous();
}

Posted by leechwin

Java Application 이나 IDE 가 실행중에 멈춰있거나, 알수없는 이유로 일정 동작에서만 멈추는 경우 JVM 에서 지원하는 Thread Dump 를 통해 어디가 문제인지 짐작해 볼 수 있다.


jps- v 혹은 ps 로 명령으로 현재 실행 중인 Java Application 의 pid 를 알아낸후, jstack 으로 스레드 덤프를 확보가능하다.

  • jps -v : jvm 관련 프로세스보기
  • jstack [pid] : 해당 프로세스 덤프확보



Posted by leechwin

 자바의 개발 목적으로 플랫폼을 크게 3가지로 나눌 수 있다.

  • Java SE(Java Standard Edition)
    • 기본적인 자바개발환경 플랫폼
    • JVM + API 개발환경
  • Java EE(Java Enterprise Edition) - J2EE
    • Java SE + Web Server 개발 환경
    • JSP, Servlet, EJB, JMS 등의 기능
    • WAS 서버라고 부르며 Jeus Glass fish, JBoss, Apache, Jetty 등의 제품이 있다.
  • Java ME(Java Micro Edition) - J2ME
    • 임베디드 장비를 위한 개발 환경
    • Java SE 의 기능을 축소


자바 개발 환경

  • JRE(Java Runtime Environment)
    • 자바 실행환경
    • JVM + Java API
  • JDK(Java Development Kit)
    • JRE + Java Tool + Java Compiler


Posted by leechwin

[JSP] Scriptlet

Java 2014.08.26 17:38

JSP 에서 html 코드내에 Java 코드를 삽입하는 Scriptlet 기술에 대해 간략히 알아보자.

  • Scriptlet
    • 스크립틀릿은 JSP 에 쓰이는 기술이다.
      • JSP는 HTML기반에 자바코드가 결합되어 있으며, 스크립틀릿인 부분은 웹서버에서 실행되고 그 결과만 웹 브라우져로 전송된다.
    • 스크립틀릿은 JSP 파일내에 <% %>으로 구성되며, 그안에는 자바 코드를 기입할 수 있다.
    • 표현식
      • <%@ %> : 지시자(page, include, taglib)
      • <% %>   : 스크립틀릿
      • <%= %> : 표현식
        • 자바식 이 대입될수 있고 자바식은 상수나 변수 이름, 연산자를 포함한 식 또는 리턴 값이 있는 메서드 호출식이 될 수도 있다.
    •  예제

      • java.util.Calendar 클래스를 import로 추가 하여 <%%> 안에서 Java 로 계산 , HTML 에서 <%=> 로 변수값을 출력하는 예제


      • <%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>

        <%@ page import="java.util.Calendar"%>

        <%

        Calendar calendar = Calendar.getInstance();

        int hour = calendar.get(Calendar.HOUR_OF_DAY);

        int minute = calendar.get(Calendar.MINUTE);

        int second = calendar.get(Calendar.SECOND);

        %>

        <html>

        <head>

            <title>Scriptlet</title>

        </head>

        <body>

          <h1>시간 <%=hour %>시 <%=minute %>분 <%=second %>초.</h1>

        </body>

        </html>


  • JSP(Java Server Page)
    • 자바로 동적 HTML을 만들기 위해 서버에서 실행되는 언어 
    • JSP 구성과 흐름도
      • 4. 웹서버는 jsp 요청이 오면 분석하여 서블릿컨테이너에 요청을 넘긴다
      • 5. 서블릿컨테이너에서는 jsp 파일에 해당하는 서블릿이 있는지 확인하고 없을 경우 jsp 파일을 서블릿으로 컴파일한다.
      • 6. 컴파일된 jsp 는 서블릿으로 변환되어 컨테이너에 적재
      • 8,9. 화면에 보일 내용을 정리해서 html 문서로 클라이언트에 전송
    • JSP/서블릿 컨테이너
      • jsp 요청이 오면 상응하는 서블릿이 처리한다.
      • jsp 요청에 상응하는 서블릿이 없다면 서블릿 컨테이너는 jsp 파일을 서블릿 소스로 변환해서 컴파일하고 서블릿으로 관리한다.
    • 서블릿
      • 웹어플리케이션(자바 웹프로그래밍)
      • 서블릿으로 컴파일된 후에는 메모리에서 처리되기 때문에 많은 사용자 접속도 원할히 처리할 수 있다.
      • jsp또는 다른 서블릿간의 데이터 공유가 쉽다. (page, request, session, application, scope 로 가능)


Posted by leechwin

Java 에서 XML 파일 Validation 수행시 기반이 되는 XSD 파일이 여러개이고 XSD 파일관의 관계가 import, include 등으로 복잡할 경우 SchemaFactory.newSchema(Source schema) 호출 Error 가 발생하는 경우가 있다.


다음의 예제로 XSD 파일 Resolve 방법에 대해 알아보자.


다음과 같이 3개의 XSD 파일이 있고 "main.xsd" 파일이 Root 가 되는 XSD 파일로 a.xsd 와 b.xsd 파일을 import 혹은 include 하고 있다.

  • a.xsd
  • b.xsd
  • main.xsd

위와 같은 구조일 경우 일반적으로 다음과 같이 Schema 를 구현한다.

// read the xsd files
FileInputStream mainStream = new FileInputStream("main.xsd");
FileInputStream aStream = new FileInputStream("a.xsd");
FileInputStream bStream = new FileInputStream("b.xsd");
Source[] sources= new Source[] { new StreamSource(mainStream), new StreamSource(aStream), new StreamSource(bStream) }

// create schema
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(sources);

// read xml file for validation
DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
documentFactory.setNamespaceAware(true);
DocumentBuilder builder = documentFactory.newDocumentBuilder();
Document doc = builder.parse(new StringInputStream(xml)); // parse the XML into a document object

// validation
Validator validator = schema.newValidator();
validator.validate(new DOMSource(doc));
위의 코드로 수행할 경우 main.xsd 내에서 xsd 파일의 참조순서가 a.xsd, b.xsd 순서가 아니라면 9라인의 factory.newSchema(sources) 에서 에러가 발생하게 된다.


위와 같이 xsd 가 여러파일과의 관계를 맺으며 복잡하게 참조관계를 갖을 경우 org.w3c.dom.ls.LSResourceResolver 인터페이스를 구현한 클래스를 SchemaFactory.setResourceResolver 함수로 등록하면 복잡한 참조관계라도 필요한 파일들을 알아서 로딩 할 수 있게 된다.

// create schema
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// set resource resolver
factory.setResourceResolver(new ResourceResolver());
Schema schema = factory.newSchema(new StreamSource(new File("main.xsd"));

// read xml file for validation
DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
documentFactory.setNamespaceAware(true);
DocumentBuilder builder = documentFactory.newDocumentBuilder();
Document doc = builder.parse(new StringInputStream(xml)); // parse the XML into a document object

// validation
Validator validator = schema.newValidator();
validator.validate(new DOMSource(doc));

class ResourceResolver implements LSResourceResolver {
    private Setresoures = new HashSet();
    @Override
    public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
         if ( resoures.contains( systemId ) ) {
                return null;
        }
        resoures.add(systemId);
        File file = new File(systemId);
        if ( file.exists() ) {
            LSInput input = new Input();
            try {
                input.setByteStream( new FileInputStream( file ) );
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            return input;
        }
        return null;
    }
}

위의 코드와 같이 LSResourceResolver 인터페이스를 구현한 ResourceResolver 에서 main.xsd 의 참조와 관련한 a.xsd, b.xsd 파일에 대한 정보요청정보를 resolveResource() 함수에서 설정이 가능하다.


 resolveResource() 함수내에서 필요한 a.xsd, b.xsd 파일의 내용이나 위치등을 설정하여 리턴하여주면 main.xsd 내의 참조관계에 따라 필요한 파일정보를 자동으로 요청하여 얻어가게 된다.


Reference: http://stackoverflow.com/questions/3499476/in-java-validate-xml-against-multiple-schemas-located-difference-server-loc

Posted by leechwin

 Java 에서 SWT Combo 박스에 Item 추가 작업을 하다가 Linux 환경에서는 text 가 제대로 나오는데 Windows 에서는 text 앞부분에 이상한문자가 붙어서 나오는 현상을 경험하게 되었다.


Windows 에서 다음과 같이 "ar-ae" 앞에 이상한 문자가 껴있었다.


디버깅을 해도 전혀 이상한 점이 없어서 삽질을 하던중 구글링을 통해 UTF-8 인코딩시 BOM(Byte Order Mark) 라는 것을 알게 되었다.

 BOM 은 UTF-8 로 인코딩되었다는 일종의 마킹인데, 윈도우즈에서 일부 프로그램에서는 BOM 을 강제로 삽입하는 경우가 있다고 한다. -_-;

 참고: http://blog.wystan.net/2007/08/18/bom-byte-order-mark-problem


 따라서 이를 제거해야 하는데, Edit Plus 와 같은 툴을 이용하는 등의 방법이 있다.

 본인은 해당 파일을 Edit Plus 에서 UTF-8 BOM 이 추가안되도록 설정한 상태에서 해당 문자를 지우고 다시 타이핑하였더니 해당 문제가 사라졌다.

 Gerrit 에서 봐도 사람이 봐서는 알 수 가 없다.


 하지만 hex viewer 로 보면 다음과 같이 EF BB BF 라는 문자가 삽입되어 있다.


 문자열이 알 수 없는 문제로 말썽을 일으킬때 한번 살펴보아야 할 부분인것 같다.


 리눅스에서 텍스트 파일 인코딩을 변경하려면 iconv uconv 명령을 사용하여 인코딩을 변경 할 수 있다.


Posted by leechwin

 Java 의 SWT 관련 Component 들을 사용하다가 다음과 같이 Invalid thread access 라는 Error 가 발생하는 경우가 있다.

   org.eclipse.swt.SWTException: Invalid thread access

at org.eclipse.swt.SWT.error(SWT.java:4282)

at org.eclipse.swt.SWT.error(SWT.java:4197)

at org.eclipse.swt.SWT.error(SWT.java:4168)

at org.eclipse.swt.widgets.Display.error(Display.java:1210)


 외부 Thread 에서 SWT Component 를  사용하려고 할 때 발생하는 에러로 SWT Component 는 UI 스레드에서만 Access 가능하다. 

 그렇기 때문에 이를 해결하려면 UI Thread 내에서 SWT Component 를 사용하도록 바꿔야 한다. 

 다음 메소드를 사용하여 UI Thread 내에서 Job 들을 수행할 수 있다.


Display.getDefault().syncExec(new Runnable() {
    @Override
    public void run() {
        // swt code
    }
});

Display.getDefault().asyncExec(new Runnable() {
    @Override
    public void run() {
        // swt code
    }
});



참고: http://stackoverflow.com/questions/5980316/invalid-thread-access-error-with-java-swt

Posted by leechwin

Java 에서 쓸 수 있는 Web Resource Compressor  관련 Framework 에 대해 간단히 소개해보고자 한다.


Web Resource Compressor  란 html, javascript, css 파일에 대한 Minifier, Beautifier 등의 기능을 수행하는 것을 말한다.


일종의 Web Resource 최적화 Framework 중 하나이다.



- Introduction


- How to use?

  • HTML Minifier - HTML Compressor 

    public void compress(InputStream source, OutputStream target) throws IOException {
        HtmlCompressor compressor = new HtmlCompressor();
        compressor.setCompressJavaScript(true); // compress inline css
        compressor.setCompressCss(true);        // compress inline javascript

        String compressedHtml = compressor.compress( IOUtil.getString( source, true ) );
        target.write( compressedHtml.getBytes() );
    }

  • XML Minifier - HTML Compressor 

    public void compress(InputStream source, OutputStream target) throws IOException {
        XmlCompressor compressor = new XmlCompressor();

        String compressedXml = compressor.compress( IOUtil.getString( source, true ) );
        target.write( compressedXml.getBytes() );
    }

  • JavaScript Minifier YUI Compressor 

    public void compress( InputStream source, OutputStream target ) throws EvaluatorException, IOException {
        InputStreamReader reader = null;
        OutputStreamWriter writer = null;
        try {
            reader = new InputStreamReader(source);
            writer = new OutputStreamWriter(target);
            JavaScriptCompressor compressor = new JavaScriptCompressor( reader,new ErrorReporter() {
                @Override
                public void warning(String message, String sourceName, int line, String lineSource, int lineOffset) {
                    if (line < 0) {
                        logger.warn(message);
                    } else {
                        String logMessage = line + " : " + lineOffset + " : " + message;
                        logger.warn(logMessage);
                    }
                }
                @Override
                public void error(String message, String sourceName, int line, String lineSource, int lineOffset)  {
                    if (line < 0) {
                        logger.error(message);
                    } else {
                        String logMessage = line + " : " + lineOffset + " : " + message;
                        logger.error(logMessage);
                    }
                }
                @Override
                public EvaluatorException runtimeError(String message, String sourceName, int line, String lineSource, int lineOffset) {
                    error(message, sourceName, line, lineSource, lineOffset);
                    return new EvaluatorException(message);
                }
            });

            // (out, linebreak, munge, verbose, preserveAllSemiColons, disableOptimizations)
            compressor.compress( writer, -1, true, false, true, false);

        } catch (EvaluatorException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        } finally {
            if ( reader != null ) { reader.close() };
            if ( writer != null ) { writer.close() };
        }
    }

  • CSS Minifier - YUI Compressor 

    public void compress(InputStream source, OutputStream target) throws IOException {
        InputStreamReader reader = null;
        OutputStreamWriter writer = null;
        try {
            reader = new InputStreamReader(source);
            writer = new OutputStreamWriter(target);
            CssCompressor compressor = new CssCompressor(reader);
            compressor.compress(writer, -1);
        } catch (IOException e) {
            throw e;
        } finally {
            if ( reader != null ) { reader.close() };
            if ( writer != null ) { writer.close() };
        }
    }

Posted by leechwin

Eclipse 에서 가끔 다른 Java 프로젝트 소스를 받거나, JDK 나 JRE 업데이트가 발생한 이후 잘 빌드가 되던 프로젝트가 빌드가 안되는 경우가 있다.


Specified VM install not found 라는 에러를 뱉어내면서 수행이 안되는 경우가 가끔 발생한다.



이때에는 다음과 같이 해결이 가능하다.

현재 작업중인 Eclipse workspace 의 경로 밑에 

/.metadata/.plugins/org.eclipse.debug.core/.launches/ 폴더내의 파일을 모두 삭제한다.

  • ../workspace/.metadata/.plugins/org.eclipse.debug.core/.launches/


이후 Run/Debug 를 수행하면 잘 동작하는 것을 볼 수 있다.


Posted by leechwin

Java 개발자라면 한번쯤은 정독해야할 Java Code Convention 에 대한 링크.



Posted by leechwin