IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  WebSphere  >

WebSphere MQ 애플리케이션에서 Python 사용하기 (한글)

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 중급

Sami Salkosuo, Application Architect, IBM 

2007 년 10 월 30 일

WebSphere MQ용 오픈 소스 확장인 PyMQI는 WebSphere MQ MQI 라이브러리에 구현된 오픈 소스 라이브러리입니다. 이 글에서는 PyMQI를 통해 WebSphere MQ용 툴과 애플리케이션을 개발하는데 까지 Python의 힘을 확장시켜 봅니다.

Python MQ 인터페이스

Python MQ Interface (PyMQI)는 IBM® WebSphere® MQ용 오픈 소스 Python 확장 라이브러리이다. PyMQI는 사용하기 쉬운 Python 인터페이스를 제공함으로써 MQI 라이브러리를 확장한다. 여기에는 C로 작성된 저수준 라이브러리가 포함되어 MQI C 라이브러리로 액세스 하고, Python 프로그래머를 위한 고급 객체 지향 인터페이스도 포함되어 있다. PyMQI를 통해 개발자들은 WebSphere MQ 툴과 솔루션에서 강력한 Python 언어를 사용할 수 있고, 모든 WebSphere MQ 개발자들에게 Python의 혜택을 제공한다. Python 홈페이지에서는 다음과 같이 언급하고 있다.

"Python은 동적인 객체 지향 프로그래밍 언어이다. 확장성 있는 표준 라이브러리가 포함되어 있으며 빠른 시간 안에 배울 수 있다. 프로그래머들은 생산성을 높일 수 있다. 이 언어는 더욱 높은 품질의, 관리가 쉬운 코드 개발을 장려한다."

PyMQI 컴파일

소셜 북마크

mar.gar.in mar.gar.in
digg Digg
del.icio.us del.icio.us
Slashdot Slashdot

PyMQI는 소스로서 배포되기 때문에, 패키지를 다운로드 하여 디렉토리에 압축을 푼 다음에 해야 할 일은 컴파일이다. 일반적으로, Python 확장은 Python과 같은 컴파일러를 사용하여 컴파일 된다. Python 배포판은 Microsoft® Visual Studio에서 구현되며, 올바른 버전이 설치되어 있다면, python setup.py build server (WebSphere MQ Server V5용) 또는 python setup.py build client (WebSphere MQ Client V5용) 명령어를 사용하여 PyMQI를 구현할 수 있다.

Microsoft Visual Studio가 없고 WebSphere MQ V6를 사용한다면, PyMQI를 사용하기 전에 다음과 같은 추가 단계가 필요하다.

  1. MinGW32(Minimalist GNU for the Windows® C-compiler)를 설치한다.
  2. WebSphere MQ C 헤더 파일을 수정한다.
  3. PyMQI를 컴파일 한다.
  4. Python 확장으로서 PyMQI를 설치한다.

또한 Windows, Python V2.5.1, WebSphere MQ V5 또는 V6 Server/Client가 컴퓨터에 설치되어 있어야 한다. 이 글에 사용되는 환경은 Windows XP 2003, WebSphere MQ V6 Server, Python V2.5.1이다.

MinGW32 설치하기

MinGW-5.1.3.exe를 다운로드 및 실행하여 설치를 시작한다. 설치 프로그램 다운로드는 웹에서 가져와서 이를 설치한다. 풀 버전은 모든 컴파일러를 설치하지만, 최소 설치로도 충분하다. MinGW를 설치한 후에, MinGW\bin-directory를 PATH 환경 변수에 추가한다.

WebSphere MQ C-헤더 파일 수정하기

WebSphere MQ V6를 사용한다면, MQ C 헤더 파일을 수정해야 한다. MinGW는 64-bit 유형 정의를 이해하지 못하기 때문이다.

텍스트 에디터에 <MQ_INSTALL_DIR>\Tools\c\include\cmgc.h 헤더 파일을 열고 Listing 1의 코드를 찾는다.


Listing 1. 대체 될 Typedefs
typedef _int64 MQINT64;
typedef unsigned _int64 MQUINT64;

Listing 1의 typedefs를 삭제하거나 주석을 제거한다. 그리고, 새로운 typedefs를 추가하고 파일을 저장한다. (Listing 2)


Listing 2. 대체 될 Typedefs
typedef long long _int64;
typedef unsigned long long _uint64;
typedef _int64 MQINT64;
typedef _uint64 MQUINT64;

PyMQI 컴파일 하기

PyMQI 소스 파일을 추출했던 디렉토리에서 명령 프롬프트를 열고 setup.py build -cmingw32 server 명령어를 사용하여 PyMQI를 컴파일 한다. 이 명령어는 PyMQI 확장을 컴파일 하여 Python 확장으로서 설치를 준비한다.

Python 확장으로서 PyMQI 설치하기

Python 확장으로서 PyMQI를 설치하려면, setup.py install --skip-build 명령어를 사용한다. PyMQI가 이제 설치되고 사용할 준비가 된다.

PyMQI를 이용한 프로그래밍

PyMQI는 함께 사용될 여러 모듈을 갖고 있다.

  • CMQC와 CMQCFC는 MQI 상수를 정의한다.
  • pymqe는 MQI에 대한 저급 Python 확장 인터페이스며, C로 작성되었다.
  • pymqi는 MQ에 대한 고급 Python 인터페이스이며 pymqe를 사용한다.

실제로, WebSphere MQ 애플리케이션을 개발할 때 pymqi가 사용된다. Listing 3은 메시지를 큐에 놓는 최소한의 코드 모습이다.


Listing 3. 메시지를 큐에 놓기
import pymqi 
qmgr = pymqi.QueueManager()
putQ = pymqi.Queue(qmgr, 'QNAME')
putQ.put('Hello world!')

큐에서 메시지를 가져오는 것 역시 간단하다:


Listing 4. 큐에서 메시지 가져오기
import pymqi 
qmgr = pymqi.QueueManager()
getQ = pymqi.Queue(qmgr, 'QNAME')
print 'Message:', getQ.get()

PyMQI는 MQCONN/MQCONNX, MQDISC, MQOPEN, MQCLOSE, MQPUT, MQGET, 같은 주요 MQI 호출을 지원한다. PCF 명령어 역시 지원되며, 트랜잭션도 지원된다.

다음 섹션에서는 PyMQI로 작성된 유용한 유틸리티를 소개하겠다. PyPut, PyGet, PyBrowse 등이 있다. TEST_QM 이라고 하는 WebSphere MQ 큐 매니저와 TESTQ 라고 하는 로컬 큐가 프로그램을 실행하기 전에 생성된다.

PyMQI 유틸리티

이 섹션에서는 PyMQI 예제를 소개하고, WebSphere MQ 개발자와 관리자를 위한 유용한 툴을 소개하겠다. PyPut은 한 개 이상의 메시지들을(인자 또는 파일로서 지정됨) 큐에 놓는 툴이다. PyGet은 큐에서 메시지를 가져와서, 이들을 시스템에 프린트 하거나 한 번에 한 메시지씩 또는 한 번에 모든 메시지를 파일로 저장한다. PyBrowse는 메시지를 검색하는데, 큐에 있는 특정 메시지를 검색할 수 있고, 일반적인 first-in-first-out (FIFO) 순서 대신 last-in-first-out (LIFO) 순서로 메시지를 검색한다.

여러분은 샘플 코드를 다운로드 하고, 그대로 사용한다. 코드를 그대로 파일에 복사하여 붙인 다음 실행한다.

PyPut

Listing 5는 PyPut용 코드이다. pymqi 외에도, PyPut은 명령행 옵션을 정의하는데 Python 모듈 OptionParser를 사용한다.


Listing 5. PyPut.py
from pymqi import *
import sys, os
from optparse import OptionParser

usage='Usage: %s [options] QMGRNAME QNAME (MSSG | FILE_NAME) [(MSG | FILE_NAME)...]'

def main(argv=None):
    if argv is None:
      argv = sys.argv
    try:
      (options,args)=parseOptions()
      if len(args)<3:
        raise MQException(1)
      qmgrName=args[0]
      qName=args[1]
      message=args[2]
      messages=args[2:]
      #open queue in specified queue manager
      qmgr = QueueManager(qmgrName)
      putQ = Queue(qmgr, qName)
      #loop through arguments and put messages
      #to a queue
      for message in messages:
        #if -f options is specified, arguments are file names
        if options.msgIsFile==True:
          if os.path.exists(message)==False:
            raise MQException(3)
          #read file contents to a message-variable
          f=open(message)
          content=f.readlines()
          f.close()
          #variable 'content' is a list of lines in the specified file
          #join lines in content-variable together as one string
          message=''.join(content)
        
        #single method call to put message to a queue
        putQ.put(message)
        if not options.quiet==True:
          print 'Message sent.' 
    except MQException, err:
      #if exception happens, print error message and exit
      print  '[ERROR]',err.errorCodes[err.msg]
      print usage % (sys.argv[0],)
      return err.code
    except MQMIError,err:
      print err
      return -1

def parseOptions():  
  parser = OptionParser(usage=(usage % ('%prog',)))
  parser.add_option("-f", 
                    "--file", 
                    action="store_true",
                    dest="msgIsFile",
                    help="Use file specified as third argument as message .", )
  parser.add_option("-q", 
                    "--quiet", 
                    action="store_true",
                    dest="quiet",
                    help="Quiet mode.", )
  (options, args) = parser.parse_args()
  return (options, args)


#MQException class that holds application specific error codes
#and error messages
class MQException(Exception):
  errorCodes={'1': 'QMGRNAME, QNAME or MESSAGE missing.',
              '2': 'Too many arguments.',
              '3': 'File does not exist.',
              '4': 'QMGRNAME or QNAME.',
              }
  code=0
  def __init__(self, code):
    self.code=code
    self.msg = str(code)

if __name__ == "__main__":
    sys.exit(main())

Listing 5의 코드는 주로 애플리케이션 로직이고, 실제 PyMQI 코드는 몇 줄 되지 않는다. 큐 매니저 얻기, 큐 가져오기, 메시지를 큐에 놓기, 에러 핸들링 등이 그것이다. 이것은 PyMQI의 힘을 보여주고 있다. Python 프로그램에서 WebSphere MQ를 사용하는 것은 사소한 문제이고 Python의 빌트인 기능들로 툴을 개발하는 것은 매우 쉽다. 예를 들어, 파일 콘텐트를 읽는 것은 네 줄의 코드로 가능하며, 자신의 툴박스에도 있는 기능이다. Python OptionParser 모듈에 있는 -h와 -help 옵션들은 명령어 도움말을 프린트한다. PyPut.py -h는 PyPut용 도움말이다.

Usage: PyPut.py [options] QMGRNAME QNAME (MSSG | FILE_NAME) [(MSG | FILE_NAME)...]

Options:
  -h, --help   show this help message and exit
  -f, --file   Use file specified as third argument as message .
  -q, --quiet  Quiet mode.

PyPut.py TEST_QM TESTQ message1 message2 명령어를 사용하여 PyPut을 실행한다. 이 명령어는 두 개의 메시지를 큐 매니저 TEST_QM에 있는 TESTQ라고 하는 큐에 놓는다.

PyPut.py 역시 스크립트에 사용될 수 있다. @for %i in ("*.txt") do call "PyPut.py" "-f" "TEST_QM" "TESTQ" "%i"는 현재 디렉토리에서 모든 txt 파일들을 루핑하고 각 txt 파일의 콘텐트를 큐에 놓는다.

PyGet

PyGet.py는 PyPut.py와 비슷하다. 단, 메시지가 시스템으로 프린트 되거나 파일로 작성된다. Listing 6은 PyGet.py용 코드 모습이다.


Listing 6. PyGet.py
from pymqi import *
import sys, os
from optparse import OptionParser

usage='Usage: %s [options] QMGRNAME QNAME'
def main(argv=None):
    if argv is None:
      argv = sys.argv
    try:
      (options,args)=parseOptions()
      if len(args)>2:
        raise MQException(2)
      if len(args)<2:
        raise MQException(4)
      qmgrName=args[0]
      qName=args[1]
      
      #open queue manager and queue
      qmgr = QueueManager(qmgrName)
      Q = Queue(qmgr, qName)      
      if options.all==True:
        moreMessages=True
        while(moreMessages):
          try:
            #get single message from queue
            message=Q.get()
            printMessage(options,message)
          except MQMIError,err:
            if err.reason==2033:
              moreMessages=False
              if not options.quiet==True:
                if not options.noDelim==True:
                  print '-'*70
                print 'No messages.' 
            else:
              raise
          
      else:
        message=Q.get()
        printMessage(options,message)
    except MQException, err:
      print  '[ERROR]',err.errorCodes[err.msg]
      print usage % (sys.argv[0],)
      return err.code
    except MQMIError,err:
      if err.reason==2033:
        #no messages
        if not options.quiet==True:
          print 'No messages.' 
          
      else:
        print err
        return err.reason

def printMessage(options,message):
  if options.saveFile==True:
    seq=1
    if not options.fileName==None:
      fileName=options.fileName
    else:
      fileName='message'
      fileName='%s%05d' %(fileName,seq)
    while os.path.exists(fileName)==True:
      fileName=fileName[:-5]
      seq=seq+1
      fileName='%s%05d' %(fileName,seq)
    f=open(fileName,'w')
    f.write(message)
    f.close()
  else:
    if not options.quiet==True:
      if not options.noDelim==True:
        print '-'*70
      print message

def parseOptions():  
  parser = OptionParser(usage=(usage % ('%prog',)))
  parser.add_option("-f", 
                    "--file", 
                    action="store_true",
                    dest="saveFile",
                    help="Save message to a file with name 'message'.", )
  parser.add_option("-n", 
                    "--file-name", 
                    dest="fileName",
                    help="File name for message. Use with -f option.", )
  parser.add_option("-A", 
                    "--all", 
                    action="store_true",
                    dest="all",
                    help="Get all messages. If messages are saved to file,"+
                     " messages have sequence number in the file name.", )
  parser.add_option("-q", 
                    "--quiet", 
                    action="store_true",
                    dest="quiet",
                    help="Quiet mode.", )
  parser.add_option("", 
                    "--no-delim", 
                    action="store_true",
                    dest="noDelim",
                    help="Do not print message delimeter.", )
  
  (options, args) = parser.parse_args()
  return (options, args)

#MQException class that holds application specific error codes
#and error messages
class MQException(Exception):
  errorCodes={'1': 'QMGRNAME, QNAME or MESSAGE missing.',
              '2': 'Too many arguments.',
              '3': 'File does not exist.',
              '4': 'QMGRNAME or QNAME missing.',
              }
  code=0
  def __init__(self, code):
    self.code=code
    self.msg = str(code)
    
if __name__ == "__main__":
    sys.exit(main())

PyPut.py에서처럼, 실제 WebSphere MQ 스팩의 코드는 몇 줄 되지 않고, 애플리케이션 로직이 소스 코드 대부분을 차지하고 있다. PyGet에 대한 도움말을 보려면 PyPut.py -h를 입력한다.

Usage: PyGet.py [options] QMGRNAME QNAME

Options:
  -h, --help            show this help message and exit
  -f, --file            Save message to a file with name 'message'.
  -n FILENAME, --file-name=FILENAME
                        File name for message. Use with -f option.
  -A, --all             Get all messages. If messages are saved to file,
                        messages have sequence number in the file name.
  -q, --quiet           Quiet mode.
  --no-delim            Do not print message delimeter.

PyGet.py에 여러 옵션들이 사용될 수 있다. 옵션들이 없다면, 큐에서 하나의 메시지를 검색하고, 이것을 시스템에 프린트 한다. 옵션 -A를 사용하면, 모든 메시지들이 큐에서 검색되는데, 이것은 큐를 청소하는데 유용하고, 개발하는 동안 자주 사용하게 된다. 예를 들어, PyGet.py -A -q TEST_QM TESTQ는 어떤 것도 시스템에 프린트 하지 않고 TESTQ를 청소한다. 이 명령어가 스크립트에 포함되면, 하나의 명령어가 큐를 청소한다.

PyBrowse

PyBrowse.py는 PyGet.py와 비슷한 특징을 갖고 있지만, 메시지를 검색하고 quite 모드를 갖고 있지 않다. 추가 옵션은 --index, --lifo, --depth 등이 있다. Index 옵션은 지정된 인덱스에서 메시지를 검색한다. Index 0은 첫 번째 메시지이고, index 1은 두 번째 메시지이다. Lifo 옵션은 메시지를 시스템에 출력하기 전에 큐에 있는 메시지를 도치시키고, 큐에 놓인 마지막 메시지를 검색할 때 사용된다. Depth 옵션은 inquery 함수를 사용하여 현재 큐의 깊이를 리턴한다.

다음은 PyBrowse의 소스 코드이다.


Listing 7. PyBrowse.py
from pymqi import *
import sys, os
from optparse import OptionParser

usage='Usage: %s [options] QMGRNAME QNAME'
def main(argv=None):
    if argv is None:
      argv = sys.argv
    try:
      (options,args)=parseOptions()
      if len(args)>2:
        raise MQException(2)
      if len(args)<2:
        raise MQException(4)
      qmgrName=args[0]
      qName=args[1]
      
      #open queue manager 
      qmgr = QueueManager(qmgrName)
      gqdesc = od( ObjectName=qName)
      Q= Queue( qmgr, gqdesc)
      qDepth=Q.inquire(CMQC.MQIA_CURRENT_Q_DEPTH)
      if options.depth==True:
        #open queue for inquire
        print 'Current depth: %d' % qDepth
        return 0

      if not options.index==None:
        if int(options.index)>=qDepth:
          raise MQException(5)

      #open queue for browsing
      Q= Queue( qmgr, gqdesc, CMQC.MQOO_BROWSE)
      msgDesc = md()
      getOpts = gmo(Options = CMQC.MQGMO_BROWSE_NEXT)
      getOpts.WaitInterval = CMQC.MQWI_UNLIMITED

      messages = []
      try:
        while 1:
          msg = Q.get(None, msgDesc, getOpts)
          messages.append(msg)
          if not options.all==True and options.index==None and not options.lifo==True:
            break

          # null MsgId and CorrelId, or cursor won't move up
          # the Q
          msgDesc['MsgId'] = ''
          msgDesc['CorrelId'] = ''
      except MQMIError, me:
        #assume that error is raised when there are
        #no more messages in queue
        pass
      
      if options.lifo==True:
        messages.reverse()
      
      if not options.all==True and options.index==None:
        messages=messages[0:1]
      
      if not options.index==None:
        printMessage(options,messages[int(options.index)])
      else:
        for message in messages:
          printMessage(options,message)
        
    except MQException, err:
      print  '[ERROR]',err.errorCodes[err.msg]
      print usage % (sys.argv[0],)
      return err.code
    except MQMIError,err:
      if err.reason==2033:
        #no messages
        print 'No messages.' 
      else:
        print err
        return err.reason


def printMessage(options,message):
  if options.saveFile==True:
    seq=1
    if not options.fileName==None:
      fileName=options.fileName
    else:
      fileName='message'
      fileName='%s%05d' %(fileName,seq)
    while os.path.exists(fileName)==True:
      fileName=fileName[:-5]
      seq=seq+1
      fileName='%s%05d' %(fileName,seq)
    f=open(fileName,'w')
    f.write(message)
    f.close()
  else:
    if not options.noDelim==True:
      print '-'*70
    print message

def parseOptions():  
  parser = OptionParser(usage=(usage % ('%prog',)))
  parser.add_option("-f", 
                    "--file", 
                    action="store_true",
                    dest="saveFile",
                    help="Save message to a file with name 'message'.", )
  parser.add_option("-n", 
                    "--file-name", 
                    dest="fileName",
                    help="File name for message. Use with -f option.", )
  parser.add_option("-i", 
                    "--index", 
                    dest="index",
                    help="Browse message in the middle of queue.", )
  parser.add_option("-A", 
                    "--all", 
                    action="store_true",
                    dest="all",
                    help="Browse all messages. If messages are saved to file,"+
                     " messages have sequence number in the file name.", )
  parser.add_option("-d", 
                    "--depth", 
                    action="store_true",
                    dest="depth",
                    help="Print just the queue depth.", )
  parser.add_option("-l", 
                    "--lifo", 
                    action="store_true",
                    dest="lifo",
                    help="Print last message first (Last-In-First-Out).", )
  parser.add_option("", 
                    "--no-delim", 
                    action="store_true",
                    dest="noDelim",
                    help="Do not print message delimeter.", )
  
  (options, args) = parser.parse_args()
  return (options, args)

#MQException class that holds application specific error codes
#and error messages
class MQException(Exception):
  errorCodes={'1': 'QMGRNAME, QNAME or MESSAGE missing.',
              '2': 'Too many arguments.',
              '3': 'File does not exist.',
              '4': 'QMGRNAME or QNAME missing.',
              '5': 'Index error. Not so many messages in queue.',
              }
  code=0
  def __init__(self, code):
    self.code=code
    self.msg = str(code)
    
if __name__ == "__main__":
    sys.exit(main())

다음은 PyBrowse용 도움말이다.

Usage: PyBrowse.py [options] QMGRNAME QNAME

Options:
  -h, --help            show this help message and exit
  -f, --file            Save message to a file with name 'message'.
  -n FILENAME, --file-name=FILENAME
                        File name for message. Use with -f option.
  -i INDEX, --index=INDEX
                        Browse message in the middle of queue.
  -A, --all             Browse all messages. If messages are saved to file,
                        messages have sequence number in the file name.
  -d, --depth           Print just the queue depth.
  -l, --lifo            Print last message first (Last-In-First-Out).
  --no-delim            Do not print message delimeter.

실행 파일 구현하기

어떤 경우, 툴의 사용자들은 Python을 설치하지 않기 때문에 배포판용 실행 파일을 갖고 있는 것이 유용하다. 다행히도, Python과 py2exe 확장을 사용하면 Python 스크립트를 Windows 실행 파일로 쉽게 변환할 수 있고, py2exe에는 하나의 디렉토리에 모든 필요한 Python 파일들이 포함되어 있다. Python 스크립트의 실행 파일을 생성하려면, 먼저 py2exe를 설치하고, setup 스크립트를 생성한다. Listing 8은 Python MQ 툴용 최소 설정 스크립트이다.


Listing 8. setup.py
from distutils.core import setup
import py2exe

setup(
    console = ["PyPut.py"],
    )

setup(
    console = ["PyGet.py"],
    )

setup(
    console = ["PyBrowse.py"],
    )

Python MQ 스크립트가 위치한 똑 같은 디렉토리에서 setup.py를 실행한다. python setup.py py2exe 명령어를 사용하고 이것이 끝날 때까지 기다린다. 이제 Python MQ 스크립트를 실행 파일로서 포함하고 있는 dist 디렉토리가 생겼고, 실행 PyMQ 툴을 위한 모든 필수 파일들이 생겼다. Dist 디렉토리를 보면, py2exe에 모든 필요한 WebSphere MQ dll 파일들이 포함되었음을 알 수 있다. 스크립트를 WebSphere MQ를 설치하지 않은 사용자들에게 배포하려면(예를 들어, 여러분의 툴이 원격 admin 툴일 경우), 이들을 남겨둔다. 그렇지 않으면, dist 디렉토리에서 python25.dll을 제외한 모든 dll 파일들을 삭제한다. 스크립트는 시스템 경로에서 MQ dll 파일들을 찾을 것이다.

요약

Python MQ Interface를 통해, Python 언어를 사용하여 WebSphere MQ용 유틸리티와 프로그램을 개발할 수 있다. Python은 신속한 개발을 위한 강력한 툴이기 때문에, PyMQI는 WebSphere MQ 프로그램에 그러한 신속함을 가져온다. 솔루션 역시 Python을 사용하여 빠르게 테스트 및 입증될 수 있다. 이 글에서 설명한 툴들은 WebSphere MQ를 사용하는 솔루션을 개발할 때 사용될 수 있는 샘플들이다. Python과 PyMQI 덕택에, 샘플 코드는 늘 진화하고, 샘플 역시도 개발자나 관리자 툴박스의 소중한 자산이 된다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
샘플 코드PyMQTools.zip5 KBHTTP
다운로드 방식에 대한 정보


참고자료



필자소개

Sami Salkosuo는 IBM Global Business Services(헬싱키)의 소프트웨어 아키텍트이다. 8년 동안 IBM에 근무했으며, Java, Python, PHP 프로그래밍 분야에 관심을 갖고 있다. Sun Certified Java Programmer, IBM Certified Solution Developer for XML and Related Technologies, IBM Certified Solution Designer for WebSphere MQ 등의 인증을 받았다. (sami.salkosuo@fi.ibm.com)




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



아니오잘 모르겠음
 


 


12345
 



위로


developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의