I/O Docs is a live interactive documentation system for RESTful web APIs. By defining APIs at the resource, method and parameter levels in a JSON schema, I/O Docs will generate a JavaScript client interface. API calls can be executed from this interface, which are then proxied through the I/O Docs server with payload data cleanly formatted (pretty-printed if JSON or XML). Basic HTML text tags are enabled in the JSON schema.
Iodocs가 좋은 점은 doc인데도 불구하고 해당 페이지에서 직접 API를 날려 볼 수 있도록 되어 있다.
설치 방법은 yum을 이용해서 간단하게 설치하는 방법도 있으나 여기서는 하나씩 설치하는 방식을 사용한다.
위의 것은 간단한 예제 시트인데 설명을 하자면 다음과 같다.
<Author> : 작성자
<LastAuthor> : 마지막 작성자
<Created> : 생성일
<Company> : 회사
<Version> : 파일 버전
<Styles> : 셀의 style을 지정한다.
<Worksheet ss:Name="Sheet1"> 요게 시트의 구분이다 요 포멧으로 묶여 있는 애들이 1개의 시트가 된다.
xml에서 아래처럼 만들면
<Worksheet ss:Name="Sheet1">
내용
</Worksheet>
<Worksheet ss:Name="Sheet2">
내용
</Worksheet>
Struts2하고 Spring2.0하고 엮어서 presentation Layer를 Struts로 사용하고 Business Layer를 Spring으로 사용하려고 세팅을 하고 Action을 만든 후에 Action에서 Spring bean을 사용하려고 하면 아래와 같은 에러가 발생하는 경우가 있다.
에러 메시지
type Exception report
message
description The server encountered an internal error () that prevented it from fulfilling this request.
exception
메일을 첨부파일과 함께 보내려면 EmailAttachment 클래스를 생성하여 파일 정보를 입력합니다.
그리고 MultiPartEmail을 통해 Simpleemail처럼 기본 메일정보를 설정한 후 MultiPartEmail의 attach() 메소드를 통해 첨부 파일을 추가하여 전송합니다.
URL을 이용해 파일 첨부하기
직접 파일을 읽어와 첨부하는 방식이 아닌 URL에서 파일 정보를 읽어와 첨부하는 방식입니다.
예제 코드는 아래를 참고하세요.
//URL정보 및 파일 정보를 설정
EmailAttachment attachment = new EmailAttachment();
이렇게 설정해서 blank.tiles를 extends 하려고 했는데.. extends를 하는 놈은 안중에도 없고, tils-defs.xml 에 있는 blank.tiles name을 가진 녀석의 /layout/blank2.vm 파일 내용만 보여지는것이다. extends 한녀석도 같이 박혀야 하는데..
그래서 vm파일을 옮겨도 보고, 바꿔도 보고.. 타일즈 문법이 틀렸는지 확인도 해보며 수십번 삽질하다가..
toolbox.xml 의 어떤 한 노드의 경로에 오타가 있단느것을 발견해서 경로를 제대로 잡아주니, extends 가 안되던 것이 에러가 해결됐다.. <!-- Struts --> <tool> <key>tiles</key> <scope>request</scope> <class>org.apache.velocity.tools.struts.TilesTool</class> </tool>
Thread.sleep()이라는 정적 메소드는 적어도 sleep 메소드에 전달된 인자로 지정한 시간 동안 스레드를 실행중인 상태를 떠나있게 만든다. 값에 100을 주면 100밀리세컨드 동안 스레드가 멈춘다.
sleep()메소드에서는 확인 예외(interruptedException)를 던지기 때문에 sleep()을 호출할 때에는 반드시 try/catch로 감싸거나 예외를 선언해야 한다.
스레드 두 개 이상이, 힙에 있는 동일한 객체를 접근하는 경우에 심각한 문제가 생길 수 있습니다.
스레드를 두 개 이상에서 똑같은 객체에 접근하면 데이터가 엉망이 될 수 있다. 예를들어, 한 스레드가 객체의 중요한 상태를 조작하는 도중에 실행중인 상태에서 벗어나면 심각한 문제가 생길 수 있다.
스레드를 사용할 때도 객체를 안전하게 만들고 싶다면 어떤 선언문들이 원자적인 절차로 처리되어야 하는지 결정해야 한다. 즉 다른 스레드가 같은 객체의 같은 메소드에 들어가기 전까지 끝까지 실행되어야만 하는 메소드를 결정해야 한다.
스레드 두개가 메소드 하나에 동시에 들어가는 일을 방지하고 싶다면 메소드 선언부에 synchronized 키워드를 추가해야 한다.
모든 객체에는 자물쇠가 하나씩 있으며 그 자물쇠에는 열쇠가 하나뿐이 없다. 대부분의 경우에 그 자물쇠에 대해서 신경을 쓸 필요가 없지만 객체에 동기화된 메소드가 있으면 자물쇠가 중요한 역할을 한다.
스레드에서 어떤 동기화된 메소드로 들어가려면 그 객체에 대한 열쇠가 있어야 한다. 열쇠가 없으면 그 스레드는 대기실 같은 공간으르 들어가서 열쇠를 슬 수 있을 때 까지 기다려야 한다. 이는 운영체제의 세마포와 비슷하다.
객체에 동기화된 메소드가 두개 이상 있어도 열쇠는 여전히 하나뿐이 없다. 어떤 스레드가 그 객체에 동기화된 메소드에 들어가면 다른 어떤 스레드도 같은 객체에 있는 동기화된 메소드에 들어갈 수 없다. 이런 제한이 있어야 데이터를 조작하는 모든 메소드를 동기함으로 데이터를 보호할 수 있다.
Socket은 서로 다른 물리적인 시스템 두 개에서 실행될 가능성이 있는 애플리케이션 두 개사이의 연결을 나타낸다.
클라이언트는 서버 애플리케이션의 IP주소와 TCP포트 번호를 알아야 한다.
TCP포트는 특정 서버 애플리케이션에 할당된 16비트 부호가 없는 정수이다. TCP 포트 번호는 서로 다른 클라이언트가 똑같은 시스템에 접속하여 그 시스템에서 돌아가고 있는 서로 다른 애플리케이션과 통신을 할 수 있게 해주는 역할을 한다.
클라이언트에서 서버 Socket을 만드는 방법으로 서버에 연결을 한다. Socket s = new Socket("127.0.0.1",4200);
일단 연결되고 나면 클라이언트는 소켓으로부터 입력 및 출력 스트림을 얻을 수 있다. 이런 스트림은 저수준 '연결' 스트림이다. sock.getInputStream();
서버로부터 텍스트 데이터를 읽고 싶다면 Socket으로부터 가져온 입력 스트림에 연쇄된 InputStreamReader와 이와 연쇄된 BufferReader를 만들면 된다.
InputStreamReader는 바이트를 받아서 텍스트 데이터로 변환해주는 '다리' 역할을 하는 스트림이다. 주로 고수준의 BufferedReader와 저수준의 Socket 입력 스트림 사이에 들어가는 가운데 고리 역할을 한다.
서버로 텍스트 데이터를 보낼 때는 소켓의 출력 스트림에 직접 연쇄된 PrintWriter를 만들면 된다. 이 객체의 Print() 또는 println()메소드를 호출하면 서버로 String을 보낼 수 있다.
서버에서는 특정 포트 번호로 들어오는 클라이언트 요청을 기다리기 위해 ServerSocket을 사용한다.
ServerSocket으로 요청이 들어오면 그 클라이언트와 Socket 연결을 함으로써 그 요청을 수락한다.
스레드
thread는 자바에서의 실행 스레드를 의미한다.
자바에서는 스레드마다 각각의 호출 스택이 있다.
대문자 T로 시작하는 Therad는 java.lang.Thread 클래스를 의미한다. Thread 객체는 실행 스레드를 나타낸다.
Thread에는 처리할 작업, 즉 해야할 일이 있어야 한다. Thread에서 처리할 작업은 Runnable 인터페이스를 구현하는 클래스의 인스턴스로 지정할 수 있다.
Runnable 인터페이스에는 메소드가 run() 하나밖에 없다. 새로운 Call stack의 맨 밑으로 들어가는 것이 바로 이 메소드이다. 즉 새롱누 스레드에서 가장 먼저 실행되는 것이 바로 run()메소드이다.
새로운 스래드를 시작하려면 Thread의 생성자에 전달 할 Runnable 객체가 필요하다.
Thread의 인스턴스를 만들긴 했는데 아직 start() 메소드를 호출하지 않았으면 그 스레드는 아직 새 스레드 상태에 있다고 부른다.
(Thred 객체의 start() 메소드를 호출하여) 스레드를 시작하면 새로운 stack이 생성되며 Runnable의 Run()메소드가 stack 맨 아래에 들어간다. 그러면 그 스레드는 이제 실행되기를 기다리고 있는 실행 가능한 상태가 된다.
JVM의 스레드 스케줄러에 의해 현재 실행중인 스레드로 선택 받으면 그 스레드는 실행중인 상태가 된다. 프로세서가 하나뿐인 시스템에서는 현재 실행중인 스레드가 하나밖에 있을 수 없다.
스레드가 실행 중인 상태에서 봉쇄된 상태로 옮겨지는 경우도 있다. 스트림으로부터 들어오는 데이터를 기다리고 있을 때, 대기 상테로 들어갔을 때, 객체에 대한 잠금이 해제되기를 기다리고 있을 때와 같은 상황에서 스레드가 봉쇄돌 수 있다.
스레드 스케줄링은 어떤 특정한 방식으로 작동한다는 보장이 없기 때문에 모든 스레드가 공평하게 기회를 부여받을 수 있으리라는 가정은 하지 말아야 한다. 스레드를 주기적으로 대기 상태로 전화시키는 방식으로 순번이 돌아가는 것에 영향을 미칠 수는 있다.
스레드 예제 소스
public class MyRunnable implements Runnable { public void run(){ go(); }
public void go(){ System.out.println("-0-;"); } } public class ThreadTester { public static void main(String[] args){ Runnable threadJob = new MyRunnable(); Thread myThread = new Thread(threadJob);
자바에서 static으로 선언하면 해당 메서드나 변수는 정적이된다. 만약 클래스의 변수를 static으로 선언하게 되면 그 변수는 객체의 변수가 되는 것이 아니라 클래스의 변수가 된다. 클래스의 변수이기 때문에 어떤 객체라도 동일한 주소의 변수를 참조하게 된다.
static의 특징
객체를 생성해도 static 변수는 메모리에 하나만 생성된다.
다른 JVM에서는 선언을 하면 다른 주소나 다른 값을 참조하지만 같은 JVM이나 WAS 인스턴스에서는 같은 주소와 같은 값을 참조한다.
CG의 대상도 되지 않는다.
지역변수에 static을 사용할 수 없다. (매서드 안에서 사용 불가능)
만약에 properties파일을 많이 사용한다면 차라리 static으로 읽어서 관리하는 것도 좋다. 왜냐하면 매번 클래스의 객체가 만들어질 때 properties를 불러오려면 부하가 많이 걸리기 때문이다.
조심해야할 것 위에 말했듯이 static은 CG 대상이 아니다. 그렇기 때문에 잘못하면 Memory Leak 현상이 발생하게 된다. 이는 시스템의 메모리를 마구 먹어서 결국은 OutofMemoryError을 발생시킬 수 있다. (Collection을 Static으로 잡고 안에 아무 데이터나 마구 넣은다음 돌려보길 바란다. 그럼 바로 GG..)
final
final은 한번 final로 지정한 값은 변하지 않는다. 변수 앞에 final이 붙으면 상수를 의미한다.