시스템 프로세스 명령어 관련하여 테스트를 진행하다 윈도우에서의 ps(process status)와 kill 명령어를 사용해야 해서~

전체 실행 중인 프로세스
C:\>tasklist

크롬이 실행중인지를 찾고 싶어서..(wildcard 사용가능)
C:\>tasklist /FI "IMAGENAME eq chrome.exe"

크롬을 죽이고 싶어서
C:\>taskkill /FI "IMAGENAME eq chrome*"



크리에이티브 커먼즈 라이센스
Creative Commons License
2010/08/27 13:40 2010/08/27 13:40

슬슬 이제 연주하는 곡들을 올려보는 욕심을 부려봐야겠습니다.

지판 연습 및 메이저 코드 연습하려고 아이폰으로 녹음한 보사노바 풍의 BG입니다.


크리에이티브 커먼즈 라이센스
Creative Commons License
2010/08/27 07:37 2010/08/27 07:37

이 클래스는 apache access로그를 regular expression으로 파싱할 수 있습니다.
This class can parse the apache access log using Java regular expression.


package test;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String txt = "127.0.0.1 - - [25/Aug/2010:15:40:26 +0900] \"GET /favicon.ico HTTP/1.1\" 404 209";

		String re1 = "^([\\d.]+)"; // IP Part
		String re2 = " (\\S+)"; // Non whitespace character(-)
		String re3 = " (\\S+)"; // Non whitespace character(-)
		String re4 = " \\[([\\w:/]+\\s[+\\-]\\d{4})\\]";  // Date
		String re5 = " \"(.+?)\"";   // Method and URL 
		String re6 = " (\\d{3})"; 	// return code
		String re7 = " (\\d+)";		// response bytes
		// 브라우저 유형, Caller의 정보 등은 별 필요없음.
		
		Pattern p = Pattern.compile(re1 + re2 + re3 + re4 + re5 + re6 + re7, Pattern.CASE_INSENSITIVE
				| Pattern.DOTALL);
		Matcher m = p.matcher(txt);

		int i = 1;
		if (m.find()) {
			System.out.print("(" + m.group(i++) + ")" + "\n");
			System.out.print("(" + m.group(i++) + ")" + "\n");
			System.out.print("(" + m.group(i++) + ")" + "\n");
			System.out.print("(" + m.group(i++) + ")" + "\n");
			System.out.print("(" + m.group(i++) + ")" + "\n");
			System.out.print("(" + m.group(i++) + ")" + "\n");
			System.out.print("(" + m.group(i++) + ")" + "\n");
		}
	}

}

크리에이티브 커먼즈 라이센스
Creative Commons License
2010/08/25 16:24 2010/08/25 16:24

답이 없네요.

AnnotationConfigApplicationContext를 이용하여 XML 전혀 없는 standalone TCP-IP 애플리케이션을 제작하고 있습니다. 문제는 SocketServer/Client를 띄우게 되는데 커스터마이즈된 환경설정을 읽어들여 띄워야 한다는 제약조건이 있습니다.

현재 @Configuration과 @Bean, @Service의 조합을 통하여 필요한 객체들을 생성하는 데 소켓 서버를 생성하는 순서는 명확하게 기준이 있어야 합니다.

1. Configuration file을 로드한다.
2. 로드된 파일의 내용을 읽어들여 시스템 정보를 취합한다.
3. 동적인 데이터베이스 쿼리를 읽어들여 메타정보를 등록한다.
4. TCP 채널을 오픈한다.
5. 채널 오픈 후 앞서 생성된 빈들을 활용하여 초기 연결 조정작업을 수행한다.

#4, #5는 해당하는 작업은 #1, #2, #3번이 없으면 안되는 작업입니다.
@Configuration과 @Import를 이용하면 작업이 되겠지만 유연성이 scan 메소드를 통한 package 자동 빈 등록의 장점이 사라지게 되는 단점이 발생을 하네요.
스캔을 해버리면 패키지명의 순서에 따라 검색 후 빈을 등록하므로, ASCII 코드의 뒤에 해당하는 알파벳으로 시작하는 패키지의 @Component를 앞선 알파벳 패키지에서 참조하면 100% NPE가 발생을 하게 되네요.

예를 들면 org.jboss.a 패키지에서 org.jboss.b 패키지의 빈을 구동시 인젝션 시키고 싶은 경우입니다.

뭐 좋은 수가 없을까요? 아는분 안계십니까~

크리에이티브 커먼즈 라이센스
Creative Commons License
2010/08/20 15:16 2010/08/20 15:16

그냥 생각나서 끄적거립니다. 혹시 나중에 까먹을까봐..

소스 -> ETL Read -> DW 저장소 -> MART, Summary 구성 -> OLAP(MART 테이블 조회) -> Report

1. 일반적으로 ETL 솔루션을 통해 원장 테이블의 구조를 그대로 DW테이블로 옮긴다. 보통 ETL에 의해 파일 저장 - 보통 DW솔루션의 처리속도(변환, 할당 등)가 빠르기 때문

2. Teradata 등의 솔루션이 파일을 로드 및 적재, 이후 작업이 끝나면 DW영역 저장
3. DW 영역에서 Mart와 Summary를 구성
4. BI(BO, MSTR등) 솔루션은 MART의 테이블을 조회하여 리포트 구성

DW프로젝트시 보통 모델링이 40%정도 비율로 소모. DW 솔루션은 각 처리 영역에 대한 CPU 비율 할당을 통해 작업 배분.
크리에이티브 커먼즈 라이센스
Creative Commons License
2010/08/18 09:07 2010/08/18 09:07

Do you want to read this in English? Comment please.

==================================
httpd.conf에 아래 설정 추가
==================================

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule slotmem_module modules/mod_slotmem.so
LoadModule manager_module modules/mod_manager.so
LoadModule proxy_cluster_module modules/mod_proxy_cluster.so
LoadModule advertise_module modules/mod_advertise.so

<Location /mod_cluster-manager>
    SetHandler mod_cluster-manager
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
</Location>

Listen 127.0.0.1:8888
<VirtualHost 127.0.0.1:8888>

    <Directory />
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1
    </Directory>

    KeepAliveTimeout 60
    MaxKeepAliveRequests 0

    ManagerBalancerName DefaultPartition
    AdvertiseFrequency 5

</VirtualHost>


=====================================
c:\Project\jboss-6.0.0.20100721-M4\server\server1\deploy\mod_cluster.sar
=====================================

mod_cluster.jar ==> mod_cluster.jar.bak 으로 Rename
mod_cluster-1.1.0.CR3-bin.tar.gz 파일에서 mod_cluster-1.1.0.CR3.jar 를
jboss-6.0.0.20100721-M4\server\server1\deploy\mod_cluster.sar 에 복사함

=====================================
server.xml에 jvmRoute 추가
=====================================
c:\Project\jboss-6.0.0.20100721-M4\server\server1\deploy\jbossweb.sar\server.xml
      <Engine name="jboss.web" defaultHost="localhost">
      ==>
      <Engine name="jboss.web" defaultHost="localhost" jvmRoute="${jboss.jvmRoute}">

jvmRoute는 설정하지 않아도 된다고 함(mod_cluster 1.1부터)
세션 ID에 jvmRoute 이름이 붙기 때문에 유용함.

=====================================
server1 시작 스크립트
=====================================
jboss.mod_cluster.proxyList=127.0.0.1:8888는
웹서버의 IP, 포트 여러 개일 경우엔 컴마로 구분하여 추가함.

run -c server1 -b 0.0.0.0 -Djboss.service.binding.set=ports-01 -Djboss.messaging.ServerPeerID=1 -Djboss.mod_cluster.advertise.enabled=true -Djboss.mod_cluster.proxyList=127.0.0.1:8888 -Djboss.jvmRoute=server1

=====================================
server2 시작 스크립트
=====================================
run -c server2 -b 0.0.0.0 -Djboss.service.binding.set=ports-02 -Djboss.messaging.ServerPeerID=2 -Djboss.mod_cluster.advertise.enabled=true -Djboss.mod_cluster.proxyList=127.0.0.1:8888 -Djboss.jvmRoute=server2


=====================================
/mod_cluster-manager 상태 확인
=====================================
아래 URL에 두개 서버가 등록되면 OK
http://localhost:8888/mod_cluster-manager?refresh=10

=====================================
로드 밸런싱 테스트
=====================================
mod_cluster-1.1.0.CR3-bin.tar.gz 파일에 데모 App이 있음

c:\Project\mod_cluster\demo\server\load-demo.war 파일을
아래 디렉토리에 복사.

c:\Project\jboss-6.0.0.20100721-M4\server\server1\deploy\load-demo.war
c:\Project\jboss-6.0.0.20100721-M4\server\server2\deploy\load-demo.war


c:\Project\mod_cluster\demo\client\run-demo.bat 를 실행함



크리에이티브 커먼즈 라이센스
Creative Commons License
2010/08/17 10:32 2010/08/17 10:32

JBoss 메시징 처리 시스템은 여러 AS버전의 변화를 거치면서 JBoss MQ, JBoss Messaging 그리고 마지막으로 HornetQ라는 이름으로 명칭 및 기능이 확장되었습니다.

HornetQ로 바뀌면서 달라진 점은 이희승씨의 도움을 받아 Netty Transport를 전단부 컨트롤러에 도입함으로써 상당한 성능 향상이 이루어졌습니다.

Spec의 Apache MQ, HornetQ 성능 자료 : http://www.spec.org/jms2007/results/jms2007.html

아키텍처가 standalone과 WAS embedded로 바뀌면서 기존의 설정만으로는 Spring에 연결이 안되는 문제가 있습니다.

여기서는 Spring과 HornetQ에 대한 통합을 설명합니다.

각설하고 일반적인 설정이므로, 실제로 돌아가는 환경 설정만을 올립니다. 크게 변경된 부분이라면 ConnectionFactory 설정이 바뀌었다는 것 정도겠습니다.




    
	
    
    
    
    
	
	
	 
	  
	   
	   
	    
	     
	    
	   
	  
	 
	
	
	
	 	
	
	
	
	 	
	  		/XAConnectionFactory
	 	
	
	
	
 		
  			/queue/LotManagerQueue
 		
	 



리스너 형태의 자바 코드는 다음과 같습니다.
package com.samsung.fpoc.jms;

import java.sql.SQLException;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import org.jboss.fpoc.dao.LotDAO;
import org.jboss.fpoc.model.Lot;


@Service("notificationsConsumer")
public class LotMessageListener implements MessageListener {
	private static final Logger log = Logger.getLogger(LotMessageListener.class);
	
	@Autowired
	private Queue logManagerQueue;

	@Autowired
	private ConnectionFactory inVMConnectionFactory;
	
	@Autowired
	private LotDAO lotDao;

	private Connection notificationsQueueConnection;

	@PostConstruct
	public void init() throws Exception {
		log.info("LotMessageListener is preparing");
		notificationsQueueConnection = inVMConnectionFactory.createConnection();
		Session notificationsQueueSession = notificationsQueueConnection
				.createSession(false, Session.AUTO_ACKNOWLEDGE);
		MessageConsumer notificationsQueueConsumer = notificationsQueueSession
				.createConsumer(logManagerQueue);
		notificationsQueueConsumer.setMessageListener(this);
		notificationsQueueConnection.start();
		log.info("LotMessageListener is started");		
	}

	@PreDestroy
	public void destroy() throws Exception {
		if (notificationsQueueConnection != null)
			notificationsQueueConnection.close();
	}
	
	public void onMessage(Message message) {
		if (message instanceof TextMessage) {
			try {
				String lotId = ((TextMessage) message).getText();
				System.out.println("The Lot Request Message is : \n" + lotId);
				Lot lot = null;
				try {
					lot = lotDao.selectLot(lotId);
				} catch (SQLException e) {
					e.printStackTrace();
				}
				log.info("RESULT : " + lot);
			} catch (JMSException ex) {
				throw new RuntimeException(ex);
			}
		} else {
			throw new IllegalArgumentException(
					"Message must be of type TextMessage");
		}
	}

	
	

}

크리에이티브 커먼즈 라이센스
Creative Commons License
2010/08/11 08:11 2010/08/11 08:11

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.MessageListener;

import org.jboss.ejb3.annotation.Depends;

/**
 * Message-Driven Bean implementation class for: LotManagerMDB
 *
 */
@MessageDriven(activationConfig =
{
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination", propertyValue="/queue/LotManagerQueue")
})
@Depends("org.hornetq:module=JMS,name=\"LotManagerQueue\",type=Queue")
public class LotManagerMDB implements MessageListener {
	
    /**
     * Default constructor. 
     */
    public LotManagerMDB() {
        // TODO Auto-generated constructor stub
    }
	
	/**
     * @see MessageListener#onMessage(Message)
     */
    public void onMessage(Message message) {
    	System.out.println("==============================");
    	System.out.println("MESSAGE : " + message);
    	System.out.println("==============================");
    }

}



@Depends annotation을 사용하지 않으면 아래와 같은 HornetQ 관련 에러가 발생을 하게 됩니다.

16:40:50,640 WARN  [HornetQActivation] Failure in HornetQ activation org.hornetq.ra.inflow.HornetQActivationSpec(ra=org.
hornetq.ra.HornetQResourceAdapter@a0b27f destination=/queue/LotManagerQueue destinationType=javax.jms.Queue ack=Auto-ack
nowledge durable=false clientID=null user=null maxSession=15): HornetQException[errorCode=105 message=Unable to validate
 user: null for check type CONSUME for address jms.queue.LotManagerQueue]

이는 Queue activation 전에 해당 queue에 액세스하는 EJB로 인하여 발생하는 문제이므로, 큐 생성 및 유효성 체크 후 EJB가 활성화되도록 하면 됩니다.

정상적으로 부팅되면 다음과 같은 메시지가 보여집니다.

16:52:54,984 INFO  [JBossASKernel] Created KernelDeployment for: poc-ejb-SpringMVCEJB.jar
16:52:55,000 INFO  [JBossASKernel] installing bean: jboss.j2ee:ear=poc-ejb-SpringMVC.ear,jar=poc-ejb-SpringMVCEJB.jar,na
me=LotManagerMDB,service=EJB3
16:52:55,000 INFO  [JBossASKernel]   with dependencies:
16:52:55,000 INFO  [JBossASKernel]   and demands:
16:52:55,000 INFO  [JBossASKernel]      jboss.ejb:service=EJBTimerService; Required: Described
16:52:55,000 INFO  [JBossASKernel]      org.hornetq:module=JMS,name="LotManagerQueue",type=Queue; Required: Described
16:52:55,000 INFO  [JBossASKernel]   and supplies:
16:52:55,000 INFO  [JBossASKernel]      jndi:null
16:52:55,000 INFO  [JBossASKernel]      Class:javax.jms.MessageListener
16:52:55,000 INFO  [JBossASKernel] Added bean(jboss.j2ee:ear=poc-ejb-SpringMVC.ear,jar=poc-ejb-SpringMVCEJB.jar,name=Lot
ManagerMDB,service=EJB3) to KernelDeployment of: poc-ejb-SpringMVCEJB.jar
크리에이티브 커먼즈 라이센스
Creative Commons License
2010/08/09 16:49 2010/08/09 16:49

현재 프로젝트에서 플랫폼 리드 겸 개발자로 작업을 하고 있는데 스프링을 이용하여 컨트롤러-에이전트 구조의 TCP기반의 모니터링 솔루션 개발하고 있습니다.

객체 관리의 문제로 인하여 JBoss로 갈까도 했지만 리소스 활용적인 측면이나 비용적인 측면에서 스프링을 이용하기로 하고, 이를 통해 솔루션에 적용하고 있습니다. 문제는 기존의 2.X의 환경설정에서 탈피하여 100% 어노테이션 기반으로 클래스들을 작성하고 있는데 객체의 수명주기 부분에 막혀버렸습니다.

매뉴얼과 포럼을 찾는데 제 검색실력이 없어서인지 딱히 현재 나타나는 현상에 대한 답이 없어 결국 코딩으로 해결하는 수밖에 없었습니다.

발단은 다음과 같습니다.
1. 에이전트가 시스템의 정보를 주기적으로 수집해야 하므로 Quartz 스케줄러를 사용하여 TCP서버인 컨트롤러 측으로 수집된 데이터를 전달합니다.
2. TCP서버가 다른 문제로 인하여 연결이 종료되면, 클라이언트는 Quartz 스케줄러를 shutdown시킵니다.
3. 클라이언트가 TCP서버 재접속 시도를 계속 하다가 서버가 살아나 연결이 성립되면 스케줄러를 다시 start시킵니다.

문제는 #3인데 스케줄러가 shutdown된 상태이면 thread running상태에서 빠져나가게 되므로 재시작을 할 수 없고 다시 factory를 통해 스케줄러 인스턴스를 생성해야 하는데, 이 때 기존의 scheduler객체를 스프링의 AnnotationConfigApplicationContext의 관리 빈 대상에서 제거시키고 새롭게 스케줄러를 등록하여야 합니다.

그런데 저 빈 녀석을 어떻게 제거시켜야 하는지, BeanDefinition을 사용하여 처리해야 하는지 모르겠네요.

결국 Proxy 클래스를 만들어 Quartz Factory와 스케줄러를 핸들링하는 클래스를 스프링서비스로 등록시키고 그것을 인젝션 시켜서 사용하고 있습니다.

import org.apache.log4j.Logger;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;


@Service
public class QuartzFactory {
	private static final Logger log = Logger.getLogger(QuartzFactory.class);
	
	private StdSchedulerFactory factory;
	private Scheduler scheduler = null;
	
	
	public QuartzFactory() throws SchedulerException {
		factory = new StdSchedulerFactory();
		start();
	}
	
	
	public Scheduler getScheduler() {
		try {
			if( scheduler != null && scheduler.isStarted() ) return scheduler;
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	public void start() {
		try {
			if( scheduler == null )
				scheduler = factory.getScheduler();
			//if( scheduler != null && !scheduler.isStarted())
			log.info("-------------- Scheduler Setup Complete -----------------");
			if( scheduler != null && !scheduler.isStarted())
				scheduler.start();
			log.info("-------------- Scheduler Startup Complete -----------------");
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}
	
	public void restart() {
		try {
			if( scheduler == null ) {
				//schedulerFactory();
				start();
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	
	public void shutdown() {
		try {
			if( scheduler != null && !scheduler.isShutdown()) {
				log.info("------- Shutting Down ---------------------");
				scheduler.shutdown(true);
				scheduler = null;
				log.info("------- Shutdown Complete -----------------");
			}
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}
}

Update : 아래의 Bean을 destory시키는 작업을 했는데도 계속 동일한 객체만 날아오는군요.
public static void removeBean(Class clazz) {
Map<String, Object> beans = ctx.getBeansOfType(clazz);
for(Map.Entry beanEntry : beans.entrySet()) {
String beanName = (String) beanEntry.getKey();
   Object bean = beanEntry.getValue();
   ctx.getBeanFactory().destroyBean(beanName, bean);
}
}
크리에이티브 커먼즈 라이센스
Creative Commons License
2010/08/05 09:09 2010/08/05 09:09