ป้ายกำกับ

วันอาทิตย์ที่ 28 สิงหาคม พ.ศ. 2554

How to Implement a .NET TypeConverter

ภาษา: Visual C++
Application Type: Windows Forms Application

ก่อนหน้านี้ ผมมีความต้องการที่จะบันทึกค่า Configuration ของโปรแกรมไว้ เพื่อให้ผู้ใช้สามารถปรับแต่งโปรแกรมให้ทำงานตามความเหมาะสมของเขาได้ เช่น โปรแกรมตรวจนับจำนวนเซลล์มะเร็ง (Cell Image Analyzer, CIA) ที่ผมกำลังพัฒนาอยู่นั้น การแสดงผลเส้นรอบรูปเซลล์ที่ตรวจพบจะใช้สีอะไร ขนาดของเส้นเท่าไหร่ จะแสดงเป็นเส้นทึบหรือเส้นประ ฯลฯ ความจริงเราก็สามารถจะ Hard code ไว้ในโปรแกรมเลยก็ได้ แต่เนื่องจากโปรแกรมนี้ ผมจะพยายามพัฒนาให้มันสามารถนำไปประยุกต์ใช้กับการนับเซลล์ชนิดอื่นๆได้ด้วย จึงคิดว่า ผู้ใช้เองก็อาจจะต้องการให้แสดงสีที่แตกต่างกันออกไป เพื่อให้อ่านผลที่รายงานได้ชัดเจนยิ่งขึ้น ผมจึงจำเป็นต้องไม่ Hard code ไว้ในโปรแกรม

อ่าน/เขียน Registry
ในขั้นตอนการอ่าน/เขียนค่า Configuration นั้น ผมเลือกใช้การอ่าน/เขียนค่าไว้ใน Registry ของผู้ใช้ โดยเราจะสามารถอ้างถึง Registry ของโปรแกรมในพื้นที่ของผู้ใช้นั้นๆได้ที่ HKEY_CURRENT_USER\Software\(Manufacturer)\(Product)\(Version) และสามารถตรวจสอบดูได้ด้วยโปรแกรม regedit.exe นะครับ

สำหรับคำสั่งของ .NET ที่เขียนเป็นแบบ Windows Forms Application นั้น เราสามารถใช้คลาส System.Windows.Forms.Application ในการทำอะไรที่เกี่ยวกับโปรแกรมของเราได้หลายอย่าง รวมถึงการใช้ Property ที่ชื่อว่า UserAppDataRegistry ในการเข้าถึง Registry ของโปรแกรมในพื้นที่ของผู้ใช้นั้นๆ เช่น
Microsoft::Win32::RegistryKey^ urk = System::Windows::Forms::Application::UserAppDataRegistry;
String^ str = (String^)urk->GetValue("MyStringValue");
 ซึ่งคำสั่ง GetValue() นี้ จะได้ค่ามาเป็น Object โดยที่ข้อมูลใน Registry นั้น เราสามารถเก็บค่าได้ 6 ชนิด คือ
  1. String (REG_SZ) - เก็บข้อความที่จบด้วย null character
  2. Binary (REG_BINARY) - ใช้เก็บข้อมูลใดๆในแบบ binary
  3. DWord (REG_DWORD) - เก็บค่า 32-bits
  4. QWord (REG_QWORD) - เก็บค่า 64-bits
  5. MultiString (REG_MULTI_SZ) - เก็บค่าเป็น array ของข้อความที่จบด้วย null character โดยจะจบข้อความทั้งหมดด้วย null character 2 ตัว
  6. ExpandString (REG_EXPAND_SZ) - เก็บข้อความที่จบด้วย null ที่มีค่าตัวแปรของระบบอยู่ด้วย เช่น %PATH% ข้อความที่อ่านมาได้นั้น จะมีการแทนค่าตัวแปรให้เรียบร้อยด้วยค่าจากตัวแปรในขณะนั้น
และเนื่องจากค่าที่อ่านมาได้จาก GetValue() นั้นเป็น Object เมื่อเราต้องการนำไปใช้ เราจะต้อง casting Object ให้ถูกต้องตรงกับชนิดของมัน ซึ่งเรารู้แน่นอนอยู่แล้วว่าเราเก็บค่าชนิดใดไว้ หรือเราอาจจะตรวจสอบชนิดของข้อมูลที่เก็บไว้ ว่าเป็นชนิดอะไรได้ด้วยคำสั่ง GetValueKind()

ปัญหาก็มีอยู่ว่า ถ้าเราต้องการที่จะเก็บค่าอื่นๆนอกเหนือจาก 6 แบบนี้ จะทำได้อย่างไร

เช่น ผมมีตัวแปรชนิด Point เก็บตำแหน่งของหน้าต่าง ซึ่งมี 2 ค่า คือ x และ y เป็นชนิด int ถ้าเราจะแยกเก็บ ก็สามารถทำได้แบบง่ายๆคือ แยกเก็บ PointX ตัวหนึ่ง PointY ตัวหนึ่ง เวลาอ่านค่ามา ก็อ่านมา 2 ครั้ง คือ GetValue("PointX") และ GetValue("PointY") จากนั้นก็เอาค่า x และ y ที่ได้มาประกอบกลับมาเป็น Point ใหม่ ซึ่งเขียนได้เลยทันที ไม่ต้องไปคิดอะไรมาก แต่เราต้องมาจัดการกับค่าตัวแปรที่ซับซ้อนเหล่านี้ทีละตัว ทั้งตอนอ่าน และตอนเขียน ซึ่งถ้าหากเรามีค่าตัวแปรหลายๆตัวที่ต้องการจะเก็บ และแต่ละตัวก็มีชนิดที่ซับซ้อนแตกต่างกันไป ก็อาจจะเกิดความยุ่งยากขึ้นได้ และอีกเหตุผลหนึ่งก็คือ ผมเองก็ขี้เกียจเขียนอะไรยาวๆ โดยเฉพาะอย่างยิ่ง ถ้าเราจะต้องกลับมาแก้

กลไก ToString()
เมื่อเราสั่ง SetValue() โดยส่ง Object ไปให้ และไม่ได้ระบุว่าให้จัดเก็บแบบไหน สำหรับ Object ที่มีชนิดไม่ตรงกับ 6 ชนิดที่ระบุไว้ คำสั่งนี้จะแปลงค่าไปเป็นข้อความ และเก็บไว้เป็นข้อความด้วยกลไกของคำสั่ง ToString() เช่น ถ้าเราสั่ง SetValue("TestPoint", gcnew Point(12,13)) ค่าที่เก็บไว้ใน Registry จะกลายเป็นข้อความ "{X=12,Y=13}" และเมื่ออ่านมาก็จะต้องอ่านมาเป็น String แล้วเราจะต้องจัดการแปลงข้อความนั้นให้กลับมาเป็น Point

กลไก ToString() นี้ เป็นกลไกที่ใช้ได้กับทุกๆ Object เพราะเป็นคำสั่งพื้นฐานของ Object เลย โดยปกติแล้ว ทั้งภาษา Java และ C# ก็มีกลไกนี้เพื่อใช้ในการแสดงตัวของ instance หรือที่เรียกว่า Reflection ทำให้สะดวกในการทำงานกับ Object ที่หลากหลาย โดยเฉพาะอย่างยิ่งการ debug ซึ่งถ้าเราต้องการให้ Object ใดๆ แสดงตัวออกมาเป็นข้อความอย่างไร เราก็ต้อง override คำสั่งนี้ อย่างเช่น Point นั้น ก็มีการ override คำสั่งนี้ กลายเป็นการให้ข้อความ "{X=?,Y=?}" ขึ้นอยู่กับค่า x และ y ในขณะนั้น

ทีนี้ปัญหาก็จะเหลือแค่ตอนที่เราจะแปลงค่ากลับจาก String มาเป็น Object ซึ่งตรงนี้ .NET ได้มีคลาส System.ComponentModel.TypeConverter ให้เราใช้ โดยที่เราจะสามารถร้องขอ TypeConverter สำหรับ Object ชนิดที่เราต้องการ เพื่อนำมาแปลงค่าได้ ถ้ามี TypeConverter ที่ตรงกันอยู่ เราก็สามารถนำมาใช้ได้เลย เช่น
Point^ t;
TypeConverter^ converter = TypeDescriptor::GetConverter(Point::typeid);
String^ strvalue = (String^)urk->GetValue("TestPoint");
if ((strvalue != nullptr) && (converter != nullptr))
    t = converter->ConvertFromString(strvalue);
กลไก TypeConverter
กลไก TypeConverter นี้มีประโยชน์อย่างมาก และใช้งานอยู่เบื้องหลังในหลายๆเรื่อง เช่น การที่ Visual Studio สามารถแสดงหน้าต่างโปรแกรมตอนที่ออกแบบ และแสดงค่าต่างๆในหน้าต่าง Property และให้เรา set ค่าต่างๆของ Component ที่เรากำลังออกแบบอยู่ได้อย่าง real-time ได้นั้น ก็ใช้กลไกอันนี้ ดังนั้น สำหรับ TypeConverter ของ Object แต่ละชนิดที่เป็นคลาสสำคัญๆของ .NET ได้มีการเขียนเอาไว้ให้เราใช้หมดแล้ว เช่น ArrayConverter, BaseNumberConverter, BooleanConverter, ByteConverter, CharConverter, ฯลฯ (สามารถดูรายชื่อได้จาก MSDN Library ใน System.ComponentModel namespace)

แต่สำหรับคลาสชนิดใหม่ๆที่เราสร้างขึ้นมาเองนั้น เราจะต้องสร้างตัว TypeConverter สำหรับคลาสของเราขึ้นมาเอง โดยจะต้องสืบทอดมาจาก TypeConverter เช่น สมมติว่า เราต้องการสร้างคลาสชื่อว่า MyPoint3D โดยมีค่า x,y และ z สำหรับเก็บตำแหน่งในสามมิติ โดยเราจะต้อง override ToString() ด้วยดังนี้
public ref class MyPoint3D
{
public:
    int x,y,z;
    MyPoint3D(int x, int y, int z)
    {
        this->x = x;
        this->y = y;
        this->z = z;
    }
    virtual String^ ToString() override
    {
        return String::Format("[{0},{1},{2}]", x, y, z); // มีรูปแบบคือ "[x,y,z]"
    }
};
จากนั้นสร้าง MyPoint3DConverter โดยสืบทอดมาจาก TypeConverter และ override คำสั่ง CanConvertFrom() CanConvertTo() ConvertFrom() แล ConvertTo() ดังนี้
public ref class MyPoint3DConverter : public System::ComponentModel::TypeConverter
{
public:
    virtual bool CanConvertFrom(ITypeDescriptorContext^ context, Type^ sourceType) override
    { 
        if (sourceType == String::typeid) {
         return true; // ถ้าเป็น String ก็สามารถ convert ได้
        }
        // ไม่อย่างนั้นก็ให้เป็นหน้าที่ของคลาสที่เราสืบทอดมา
        return TypeConverter::CanConvertFrom(context, sourceType);
   }

   // Overrides the ConvertFrom method of TypeConverter.
   virtual Object^ ConvertFrom(ITypeDescriptorContext^ context,
      CultureInfo^ culture, Object^ value) override
   {
       if (value->GetType() == String::typeid) {
           String^ str = (String^)value;
           array<Char>^ chars = {'[', ',', ']'};
           array<String^>^ v = str->Split(chars);
           return gcnew MyPoint3D(int::Parse(v[1]), int::Parse(v[2]), int::Parse(v[3]));
      }
      return TypeConverter::ConvertFrom(context, culture, value);
   }

   // Overrides the ConvertTo method of TypeConverter.
   virtual Object^ ConvertTo(ITypeDescriptorContext^ context,
      CultureInfo^ culture, Object^ value, Type^ destinationType) override {
          if (destinationType == String::typeid) {
              return value->ToString();
      }
      return TypeConverter::ConvertTo(context, culture, value, destinationType);
   }
};
เมื่อสร้างเสร็จแล้ว สิ่งสำคัญคือ เราจะต้องลงทะเบียนให้ TypeDescriptor รู้ว่า จะต้องใช้ MyPoint3DConverter สำหรับ convert MyPoint3D ตอนเรียกใช้ TypeDescriptor::GetConverter() โดยขั้นตอนตรงนี้ ทาง Microsoft ได้ซ่อนกลไกการทำงานไว้ และให้เราทำโดยการระบุ TypeConverter Attribute ให้กับคลาส ผ่านทางการประกาศ attribute ที่หัวของคลาสดังนี้
ref class MyPoint3DConverter;

[TypeConverter(MyPoint3DConverter::typeid)]
ref class MyPoint3D
{
...
};
และเนื่องจาก การประกาศคลาส MyPoint3DConverter นั้น เราประกาศอยู่หลังคลาส MyPoint3D จึงทำให้เวลาคอมไพล์บรรทัดที่ประกาศ TypeConverter Attribute จะเกิด error ขึ้น เราจึงต้องเพิ่มบรรทัดที่ประกาศชื่อ MyPoint3DConverter ที่บรรทัดก่อนหน้ามันอีกทีหนึ่ง

สุดท้าย การใช้งาน
RegistryKey^ urk = Application::UserAppDataRegistry;
MyPoint3D^ a = gcnew MyPoint3D(12,13,14);
MyPoint3D^ b;
String^ stra = a->ToString(); // ได้ข้อความ "[12,13,14]"
String^ strb;
urk->SetValue("Test", a); // ปรากฏข้อความ "[12,13,14]" ใน registry
TypeConverter^ converter = TypeDescriptor::GetConverter(MyPoint3D::typeid);
String^ strvalue = (String^)urk->GetValue("Test");
if ((strvalue != nullptr) && (converter != nullptr)) {
    b = (MyPoint3D^)converter->ConvertFromString(strvalue); // ได้ Object ใหม่ที่มีค่า x=12,y=13,z=14
    strb = b->ToString(); // ได้ข้อความ "[12,13,14]"
}

สุดท้ายแล้ว หวังว่าบทความนี้จะทำให้ผู้ที่สนใจสามารถนำไปประยุกต์ใช้กับงานด้านอื่นๆได้อีกนะครับ

วันศุกร์ที่ 26 สิงหาคม พ.ศ. 2554

การติดตั้ง Rational Team Concert

ก่อนหน้านี้ผมได้เขียนถึงเรื่องการเสียเวลาไปเดือนกว่าๆ กับการพยายามใช้ Rational Team Concert ไปแล้ว ครั้งนี้ ผมก็อยากจะแนะนำการติดตั้งโปรแกรมนี้แบบง่ายๆสั้นๆ เพื่อให้ผู้ที่สนใจได้เริ่มต้นทดลองใช้โปรแกรมนี้ได้ทันที โดยไม่ต้องมาเสียเวลามากมายอย่างผมนะครับ โดยขอเน้นไปที่การติดตั้งบน Windows 7 เท่านั้น

เริ่มจากการดาวโหลดโปรแกรม
โปรแกรมนี้สามารถดาวโหลดได้ที่เว็บ Jazz.net สำหรับรุ่นที่แนะนำในบทความนี้คือ Rational Team Concert 3.0.1 โดยสามารถเลือก Platform ที่ต้องการ และเลือกรูปแบบของ License ได้ ตอนนี้ IBM ให้ Free 10 Developer License สามารถดาวโหลดในหน้าเดียวกันได้เลย แต่ถ้าหากต้องการดาวโหลดแบบเต็มๆ ก็เลือกหัวข้อ More download options ที่อยู่ข้างๆ Platform List นะครับ

อ้อ ตอนดาวโหลดจะต้องสมัครเป็นสมาชิกของเว็บก่อน ถึงจะดาวโหลดได้นะครับ

หมายเหตุ: หากดาวโหลดแบบไม่เต็ม คือเป็น Web Installer นั้น ไฟล์จะมีขนาดเล็กก็จริง แต่ตอนที่เราติดตั้ง จะต้องออนไลน์เพื่อที่จะดาวโหลดไฟล์ที่เหลือมาติดตั้งอีกทีหนึ่ง ซึ่งจะต้องใช้ user ที่ลงทะเบียนไว้ในตอนที่เราดาวโหลดมาด้วย

ติดตั้งโปรแกรม
สำหรับ Platform ที่สามารถใช้งานได้นั้น เขาแนะนำว่าควรจะเป็น 64 บิต OS และมีหน่วยความจำอย่างน้อย 4GB เช่น ถ้าติดตั้งบน Windows ก็ควรจะเป็น Windows Server 2008 R2 หรือ 2003 SP2 ก็ได้ แต่เนื่องจากโปรแกรมนี้เป็น Java Web Application ทำงานอยู่บน Tomcat ซึ่งสามารถใช้งานบน 32 บิต OS ได้อยู่แล้ว สำหรับการทดลองใช้ ไม่ได้ใช้งานหนักๆ ก็สามารถทำงานได้ แต่อาจจะอืดๆนิดๆ

เมื่อแตกไฟล์ออกมาแล้ว ให้รันโปรแกรม launchpad โดยคลิ๊กเมาส์ปุ่มขวา แล้วเลือก Run as administrator เพื่อให้มีสิทธิ์ในการติดตั้งโปรแกรม ซึ่งจะแสดงหน้าต่างรายชื่อโปรแกรมที่จะติดตั้ง ให้เลือกหัวข้อ
Jazz Team Server with Required Base Keys, including Trials, and CCM, QM and RM Applications
ซึ่งจะเป็นการติดตั้งโปรแกรมทั้งหมดในคราวเดียว โดยจะเริ่มจากการติดตั้ง IBM Installation Manager ก่อน แล้วค่อยติดตั้งโปรแกรมอื่นๆจากตัวนี้อีกทีหนึ่ง

สำหรับผู้ที่ดาวโหลดไฟล์ติดตั้งชุดที่มีชื่อเป็น Web เช่น RTC-Web-Installer-Win-3.0.1.zip นั้น ตอนติดตั้ง โปรแกรมจะดาวโหลดส่วนอื่นๆจากอินเตอร์เน็ตมาเพิ่ม ซึ่งจะต้อง Connect ไปที่ jazz.net ด้วย user ที่ลงทะเบียนไว้ และออนไลน์อยู่ตลอดในตอนที่ติดตั้งโปรแกรมนะครับ

Start/Stop Server
เมื่อติดตั้งโปรแกรมเรียบร้อยแล้ว จะปรากฏเมนูโปรแกรม Jazz Team Server และหัวข้อ Start และ Stop Server ให้สามารถสั่งให้ Server ทำงานได้ เราจะต้องกดเลือกหัวข้อ Start ด้วยเมาส์ปุ่มขวา เพื่อเลือก Run as administrator นะครับ เพราะจะได้รันด้วยสิทธิ์ในการเขียน/อ่านข้อมูลในโฟลเดอร์ Program Files ได้

เมื่อ Start ครั้งแรก ควรจะรอให้ Tomcat Deploy โปรแกรมส่วนต่างๆให้เรียบร้อยก่อน ซึ่งมันจะแสดงข้อความว่ากำลังติดตั้ง admin.jar, ccm.jar, qm.jar, rm.jar ให้เราเห็นในหน้าต่าง ควรจะรอจนกว่าจะขึ้นข้อความว่า
INFO: Server startup in ???? ms
? คือเวลาที่ใช้ในการ start ระบบ สำหรับครั้งแรกจะนานหน่อย แต่ครั้งถัดไปจะเร็วขึ้น

เมื่อจะจบการทำงาน ก็ให้เลือกเมนู Stop ด้วยสิทธิ์ของ admin เหมือนตอน Start นะครับ

Setup Server
จากนั้น เราสามารถล็อกอินเข้าสู่ระบบเพื่อทำการ Setup ได้ด้วย URL https://localhost:9443/jts/setup และใช้ User ID: ADMIN ส่วน Password ก็ใช้ ADMIN เช่นเดียวกัน จากนั้นจะปรากฏขั้นตอนต่างๆอยู่ทางซ้าย และปุ่ม Back, Next, Finish อยู่ด้านล่าง ทำการตั้งค่าตามขั้นตอนข้างล่างนี้ไปเรื่อยๆ ส่วนใหญ่แล้วจะกด Next แต่ควรจะรอให้หน้าเว็บ แสดงข้อความทดสอบสีเขียวขึ้นมาก่อน จึงจะทำขั้นต่อไปได้ ถ้ามีข้อผิดพลาดอะไร จะขึ้นข้อความสีแดง หรือข้อความเตือนก็จะเป็นสีเหลือง
  1. RATIONAL JAZZ TEAM SERVER (/jts)
    1. Introduction - กด Next
    2. Configure Public URI - ป้อน URI ที่จะใช้อ้างอิง โดยระบบจะใช้ URI นี้ตลอดไป ถ้าใช้งานเฉพาะในเครื่องตัวเองควรใช้ URI เป็น https://localhost:9443/jts เหมือนที่เราใช้ล็อกอินเข้ามา โดยจะมีข้อความเตือน เพราะ localhost ไม่ใช่ public URI แต่ไม่มีปัญหาใดๆ สามารถ กด Check Box ยอมรับ และกด Next ต่อไปได้
    3. Configure Database - จะมีการ config ฐานข้อมูลอัตโนมัติ สำหรับการใช้งาน Derby Database Server โดยเราไม่ต้องแก้ไขค่าใดๆ เมื่อขึ้นข้อความสีเขียวแล้ว สามารถกด Next ต่อไปได้เลย แต่ถ้าต้องการใช้งานร่วมกับฐานข้อมูลชนิดอื่น เช่น Oracle, Microsoft SQL Server ก็สามารถเปลี่ยนได้ แต่ต้องศึกษาวิธีการตั้งค่าให้ละเอียดจากคู่มือ Rational solution for Collaborative Lifecycle Management
    4. Enable E-Mail Notification - ไม่จำเป็นต้องตั้งค่าใดๆ กด Next ต่อไป
    5. Register Application - จะมี 2 ขั้นตอนคือ การตรวจสอบ Application และการลงทะเบียน ให้รอจนกว่ารายชื่อ Application จะแสดงครบ คือ /rm, /ccm, /qm และ /admin จากนั้นก็กดปุ่ม Register Applications ให้รอจนกว่าจะขึ้นข้อความสีเขียว แสดงว่าลงทะเบียน Application ได้แล้ว กดปุ่ม Next ต่อไปได้เลย
    6. Setup User Registry - หน้านี้จะเป็นการลงทะเบียนผู้ใช้ที่เป็นผู้ดูแลระบบ แทนที่ ADMIN ที่เราใช้ล็อกอินเข้ามาครั้งแรก ซึ่ง ADMIN จะถูกยกเลิกการใช้งานไป ให้ป้อน user name password ตามที่ต้องการ แล้วกด Next ต่อไป แต่หากต้องการทดลองใช้งานความสามารถด้านต่างๆ ก็สามารถเลือก Activate Trial License ต่างๆได้ ซึ่งให้ทดลองใช้ได้ 60 วัน ถ้าเราไม่ Activate ในขั้นตอนนี้ เราสามารถไป Activate ภายหลังได้
    7. Configure Data Warehouse - จะต้องป้อนชื่อ user name password สำหรับ user ที่ใช้ในการจัดการภายในของฐานข้อมูล Data warehouse โดย user นี้จะใช้งานเชื่อมโยงทั้ง CCM, QM และ RM จึงควรใช้ชื่อเดิม เช่น dw_user ตามตัวอย่างที่แนะนำไว้ และ password จะใช้อะไรก็ได้ โดยจะต้องกรอกในขั้นตอนถัดๆไปด้วย จากนั้นก็กด Next เป็นอันสิ้นสุดการ config server
  2. CHANGE AND CONFIGURATION MANAGEMENT (/ccm)
    1. Configure Database - สำหรับฐานข้อมูล Derby จะมีการ configure อัตโนมัติ สามารถกด Next ต่อไปได้เลย
    2. Configure Data Warehouse - ป้อนรหัสผ่านให้ถูกต้อง แล้วกด Next
    3. Finalize Application - กดปุ่ม Finalize Application Setup รอจนกว่าจะขึ้นข้อความสีเขียว เป็นอันสิ้นสุดการ configure CCM กด Next
  3. QUALITY MANAGEMENT (/qm)
    1. Configure Database - สำหรับฐานข้อมูล Derby จะมีการ configure อัตโนมัติ สามารถกด Next ต่อไปได้เลย
    2. Configure Data Warehouse - ป้อนรหัสผ่านให้ถูกต้อง แล้วกด Next
    3. Finalize Application - กดปุ่ม Finalize Application Setup รอจนกว่าจะขึ้นข้อความสีเขียว เป็นอันสิ้นสุดการ configure QM กด Next
  4. REQUIREMENT MANAGEMENT (/rm)
    1. Finalize Application - กดปุ่ม Finalize Application Setup รอจนกว่าจะขึ้นข้อความสีเขียว เป็นอันสิ้นสุดการ configure RM กด Next
  5. LIFECYCLE PROJECT ADMINISTRATION (/admin)
    1.  Finalize Application - กดปุ่ม Finalize Application Setup รอจนกว่าจะขึ้นข้อความสีเขียว เป็นอันสิ้นสุดการ configure ADMIN กด Next
  6. FINISH SETUP
    1. Summary - แสดงหน้าสรุป สามารถเลือกที่จะเริ่มสร้าง User สร้าง Project หรือจบการทำงานด้วยการกดปุ่ม Finish แล้วค่อยล็อกอินเข้ามาจัดการภายหลังได้
เข้าใช้งาน
เข้าใช้งานระบบได้จาก Public URI ที่ตั้งไว้ในขั้นตอนก่อนหน้านี้ นั่นคือ https://localhost:9443/jts โดยล็อกอินด้วย user ใหม่ที่สร้างขึ้น

เพิ่ม Client Access License
หากต้องการเพิ่ม Client Access License เช่น Free 10 Developer License ที่ IBM ให้ฟรีนั้น สามารถเข้าไปเพิ่มได้ที่ Server Administration/License Key Management ตรงหัวข้อ Client Access License Types กด Add แล้วเลือกไฟล์ License ที่ดาวโหลดมา กด Finish ก็จะมีหัวข้อของ 10 Developer เพิ่มเข้ามา

ทั้งหมดนี้ คือขั้นตอนการติดตั้ง Rational Team Concert สำหรับการใช้งานส่วนอื่นๆนั้น ไว้ค่อยมาเขียนต่อคราวหน้านะครับ

วันศุกร์ที่ 19 สิงหาคม พ.ศ. 2554

เสียเวลาไปเดือนกว่าๆ กับการพยายามใช้ Rational Team Concert

เมื่อประมาณเดือนกว่าๆที่ผ่านมา ผมได้พยายามหาโปรแกรมที่ช่วยในการบริหารจัดการโครงการมาใช้ ส่วนหนึ่งนั้นเป็นเพราะในเทอมนี้ ได้สอนวิชา Software Engineering จึงอยากจะเอามาแนะนำให้นักศึกษาได้เรียนรู้ ส่วนหนึ่งก็เพราะมีโครงการวิจัยที่ต้องจัดการอยู่หลายโครงการ ก็เลยนึกถึงโปรแกรม Rational Rose ของ IBM ที่สมัยก่อน(ประมาณ 10 กว่าปีมาแล้ว) เคยใช้ในการออกแบบโปรแกรม สร้าง UML Diagram แต่สมัยนี้ ทาง IBM ได้สร้างเป็นโปรแกรมใหม่ชื่อว่า Rational Team Concert (RTC) หรือจะเรียกชื่อเต็มๆซึ่งเป็นโปรแกรมชุดใหญ่ชื่อว่า Rational solution for Collaborative Lifecycle Management (CLM)

โปรแกรมนี้จะทำงานเป็น Server โดยมีแกนของระบบชื่อว่า Jazz Foundation หรือ Jazz Team Concert (JTC) ซึ่งพัฒนาเป็น Open Source ในโครงการที่ชื่อว่า  Jazz Project (jazz.net) และที่น่าสนใจมากก็คือ สถาปัตยกรรมของระบบ จะมี Jazz Foundation เป็นโครงสร้างพื้นฐาน จากนั้นก็จะมีโมดูลต่างๆสวมเข้ามาในระบบคล้ายการ Plug-In ทำให้กลายเป็นระบบใหญ่ที่ทำโน่นทำนี่ได้หลายอย่าง ใครสนใจเจ้า Jazz Foundation ก็สามารถดาวโหลดได้ที่ https://jazz.net/downloads/jazz-foundation/

ปัญหาก็มีอยู่ว่า ผมได้ติดตั้งโปรแกรมนี้ตั้งแต่เมื่อเดือนกว่าๆที่ผ่านมา โดยติดตั้งโปรแกรมนี้บน Ubuntu 10.04 แต่เมื่อถึงขั้นตอน setup ก็เกิดปัญหาขึ้นกับฐานข้อมูล คือ โปรแกรมจะสร้างฐานข้อมูลอยู่นาน และบางครั้งก็ไม่สำเร็จ ทำให้เกิด error ต่างๆตามมา ผมก็ลบฐานข้อมูลทิ้งแล้ว setup ใหม่อยู่หลายรอบ ก็ได้บ้างไม่ได้บ้าง ครั้งที่ได้ เมื่อใช้งานไปสักพัก ระบบก็รวน เกิด error ต่างๆตามมาอีก ผมจึงคิดว่า ปัญหาน่าจะเป็นที่ตัว Derby ที่เป็น database server ซึ่งอาจจะไม่เหมาะกับโปรแกรมใหญ่ๆอย่าง RTC นี้ ซึ่งโปรแกรมนี้สามารถใช้งานร่วมกับ database server ได้หลายยี่ห้อ เช่น Oracle, Microsoft SQL และ DB2 และผมคิดว่า ฐานข้อมูลของ IBM น่าจะใช้งานร่วมกับโปรแกรมของ IBM ได้ดี ผมจึงเลือกเอา DB2 Express-C มาลง ซึ่ง IBM ใจดีให้ใช้ฟรีอีกด้วย แต่ผมเองก็ไม่เคยใช้งาน DB2 มาก่อน ก็เลยต้องเสียเวลาศึกษาวิธีการติดตั้งและใช้งานอยู่พักใหญ่ เสียเวลาไปอีกเป็นสัปดาห์ ก็ติดตั้งและ setup ได้บ้างไม่ได้บ้างเหมือนเคย

ก็คิดว่าอาจจะเป็นปัญหาที่ Java คือ โปรแกรมนี้ใช้ JRE ของ IBM เอง และทุกครั้งที่ shutdown server ก็มักจะมีข้อความ stack overflow โผล่มาให้เห็นทุกครั้ง ผมจึงพยายามเปลี่ยนให้ RTC มาใช้ JRE ของ Sun แทนโดยเข้าไปแก้ไข script ตอน startup server แต่ผลลัพธ์ที่ได้คือ โปรแกรมรันได้ แต่ไม่ตอบสนองต่อ browser เลย ผมก็พยายามอยู่หลายวิธี จนผ่านไปเดือนกว่าๆ จนผมแทบจะหมดความอดทน กำลังคิดว่า ถ้ายังแก้ปัญหาไม่ได้ คงต้องหาโปรแกรมตัวอื่นมาใช้แทนซะแล้ว แต่ก็น่าเสียดายอยู่ เพราะโปรแกรมของ IBM ตัวนี้ มีชื่อเสียงมาก มีความสามารถสูง และทำได้หลายอย่าง

และแล้ว ผมก็ตามหาความสำเร็จจนพบ แต่ก็เป็นความสำเร็จที่ไม่ค่อยจะประทับใจสักเท่าไรนัก เพราะมันเกิดจากเรื่องเล็กๆที่ไม่น่าจะเกิดขึ้นเลย

ปัญหานี้ความจริงแล้ว ผมก็ได้ทำตามขั้นตอนการติดตั้งที่เขาบอกไว้แล้ว คือ เนื่องจากโปรแกรมจะเปิดไฟล์เป็นจำนวนมาก และโดยปกติแล้ว Linux จะตั้งค่าจำนวนไฟล์ที่เปิดได้ไว้ที่ 1024 ซึ่งก็มากโขอยู่ แต่ตามคู่มือบอกว่า ให้ตั้งไว้เป็น 65536 โดยให้ไปแก้ไขที่ /etc/security/limits.conf และสามารถตรวจสอบจำนวนไฟล์ที่จำกัดได้จากคำสั่ง ulimit -n ซึ่งจะได้ค่า 65536 กลับมา แสดงว่าเรากำหนดไว้ถูกต้องแล้ว และก็ไม่น่าจะมีปัญหาอะไร

แต่...ปัญหาก็คือ ทุกๆครั้งที่ผมจะ start server ผมก็จะเปลี่ยนไปเป็น root ด้วยคำสั่ง sudo su และผมก็ไม่เคยเอะใจเลยว่า มันจะทำให้ ulimit กลับมาเป็น 1024 ทำให้เมื่อโปรแกรมทำงานไปจนถึงขีดจำกัดนี้ มันก็ทำงานต่อไม่ได้ ทำให้เกิด error ต่างๆแบบ random ไม่แน่นอน สร้างปัญหาปวดหัวแบบไม่ซ้ำรูปแบบได้ตลอดเวลา สุดท้าย ผมก็เลยต้องเพิ่มคำสั่ง ulimit -n 65536 เข้าไปใน startup script เพื่อแก้ปัญหานี้ แล้วทุกอย่างก็ทำงานได้อย่างราบรื่น เฮ้อ...

หลังจากแก้ปัญหาได้แล้ว ผมก็เลยโพสปัญหาเข้าไปที่ Jazz Forum ปรากฏว่า มีคนพบปัญหานี้มาแล้วเช่นกัน ตั้งแต่เมื่อเดือนกุมภาพันธ์ และมีข้อแนะนำ เฉพาะสำหรับ Ubuntu ว่า มีปัญหาการใช้เครื่องหมาย * ในไฟล์  /etc/security/limits.conf ที่เดิมนั้นคู่มือแนะนำให้ใช้ * แทน user ทุกๆคน แต่สำหรับบน Ubuntu (หรือไม่แน่ใจว่าเป็นกับ Debian ด้วยหรือเปล่า) จะไม่มีผลต่อ root