• 카테고리
    • 전체 글

    • 카테고리1
    • 카테고리2
    • 카테고리3
    • 카테고리4
  • 태그
  • 방명록

'분류 전체보기'에 해당되는 글 1246건

  • 2014.01.09 Log4Net 설정 방법 2
  • 2013.08.28 OLEDB 개체(Excel, Access) 호환성 높이기 7
  • 2013.08.27 아.. 놔...그럼 인터파크 비스킷 교환행사라도 해라!
  • 2013.07.10 Alfresco 문서 변환 오류 문제 6
  • 2013.06.20 MS Access DB 한계 2
  • 2013.06.10 SKT T-Login (와이브로) 쓰면 바보다.... 3
  • 2013.06.05 갤럭시S3 3G 최적화 4
  • 2013.05.29 DataTable GetChange 사용법 1

Log4Net 설정 방법

기술자료/.NET 2014. 1. 9. 12:47

log4j 라는 Apache 프로젝트가 있다. ( http://logging.apache.org/log4j )
java 내에 동작하는 각종 Log 내용을 쌓기 위한 모듈인데, 내부적으로 어떠한 설계로 구성되었는지는 살펴보지 않아, 잘은 모르지만, 성능적 저하 없이 많은 양의 Log 관리에 훌륭하게 대처 할 수 있다. 또, Log로 남겨지는 형태를 단순 Text 파일 형식에서 부터 DB 파일까지 그 대응적 능력이 우수하다.

.NET 프로그램에서도 이 강력한 log4j를 사용할 수 있는데, 그 도구가 바로 log4net 이다. ( http://logging.apache.org/log4net/ )

여기에 쓸 내용은 지금까지 Application 내에 적용하면서 진행되었던 사항들을 적용 순서 대로 나열할 예정이다. 그래서 그 순서가 log4net에 대한 기초와는 다르다. 그러다 보니, 독자가 현재 적용 중인 Project나 구성과는 사뭇 다를 수 있으며, 스스로 잘못 이해한 부분으로 인한 오류도 있다.
더욱이 Web-Base가 아닌 WinForm-Base로 제작하면서 익힌 기능이다 보니, Web 기반의 구성과 일부 차이가 발생할 수 도 있다. 이점을 이해하면서 살펴보면 좋을 것 같다. 또, 이 글 외에도 많은 log4net에 대한 예제, 구성 이야기들을 살펴볼 수 있으므로, 사뭇 달라도, 자신의 적용과 유사한 다른 글들을 찾아보기도 쉬울 것이다.

 

log4net 접근 시작

최초에는 독자적으로 log 파일을 쌓고 구성했다. 그런데, 문제는 Single Thread 기반의 Application이다 보니, 로그 쌓는데, 의외로 많은 Process Time을 잡아 먹는 문제점이 발생했다. 로그는 좀 더 Detail 하게 쌓고 싶었지만, 그 성능적 문제로 인해 log를 쌓기에 두려움까지 얻게 되었다.

그러다가, java 관련 프로젝트를 수행하면서 log4j 에 대한 접근을 좀 하고 나니, log 쌓는 작업에 대한 대치성에 대해서 고민하게 되었고, 잠시 짬을 두어 log4net을 살펴보았다.

오픈 소스다 보니, 소스 자체를 공개하고 있으며, 다양한 Platform에 대한 컴파일이 이미 되어 있어, 사실 자신이 원하는 프로젝트에 대한 Platform에 맞추어 미리 컴파일된 버전을 바로 연결해서 사용가능 하다.
http://logging.apache.org/log4net/download_log4net.cgi 에서 다운로드 페이지 내에, Binaries 중,
log4net-1.2.13-bin-newkey.zip 을 다운 받았다. 그 안을 열면 여러가지 폴더가 있는데, bin 폴더에 들어가, 자신의 .NET Framework 버전에 맞추어 들어가면, log4net.dll 이 있는데, 이 파일만 꺼내오면 된다.

이제 자신의 Project 내에 저 파일을 복사( 개인적으로는 Solution 폴더 바로 아래에 Assembly 폴더를 만들어서 그 안에 복사) 해준다.

이제 자신의 프로젝트에 참조를 건다.

참조 건 뒤에 빌드 할 때 마다 파일이 복사되서 전달 될 수 있도록 Copy Local 이 True인지도 살펴본다.
(간혹 이 부분을 누락해서, 배포할 때, DLL이 빠져서 실제 이 배포본을 받는 사람은 실행이 안되는 문제가 발생하기도 한다.)

그리고 로그를 쌓는 로직을 작성한다.

그리고 이제 소스 상에서 다음과 같이 추가한다.

여기서는 제일 만만한 Form1.cs 파일을 열고 수정한다.

최초로 열면 아래와 같은 소스이다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyTestProject
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}

이제 이 소스를 다음과 같이 수정한다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyTestProject
{
    public partial class Form1 : Form
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        public Form1()
        {
            log.Info("Form Init Start");    
            InitializeComponent();
            log.Info("Form Init End");
        }
    }
}

이제 프로젝트를 실행해보자.

분명 로그를 쌓으라고는 했으나, 로그가 쌓이지는 않는다. 당연하다.
로그를 쌓기 위한 log 개체는 만들었다.

private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

하지만, 위의 개체에다 아무리 로그를 쌓으라고 해도 어디다가 어떻게 쌓아야 될지에 대한 설정이 없으므로 쌓일리 없다.
즉 로그가 모두 무시되는 상황. 이를 위해서 설정을 해주어야 한다.

 

이 설정 방법은 크게 두 가지가 있는데, 하나는 정적인 방법이고, 다른 하나는 동적인 방법이다.

그 방법이 아래와 같다.

 

로그 쌓기 설정 그 방법 1.

구글을 통해 이런 저런 설정 관련 예제를 받으면 대부분은 .config 파일에다 그 설정을 넣는 방법을 제공한다.
즉 응용 프로그램 프로젝트의 경우 App.config 파일이 그 해당 파일인데 응용 프로그램 프로젝트를 최초로 만들 때는 없는 경우가 많다. 그 경우 새 항목을 추가해서 새로 만들어 주도록 한다.

이제 App.config 파일을 열어보면, 설정을 위한 XML 파일이 열린다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration?> 
</configuration?>

이 안을 다음과 같이 설정한다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration?> 
  <configsections?>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /?>
  </configsections?>
  <log4net?>
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender"?>
      <file value="example.log" /?>
      <appendtofile value="true" /?>
      <maximumfilesize value="100KB" /?>
      <maxsizerollbackups value="2" /?>
      <layout type="log4net.Layout.PatternLayout"?>
        <conversionpattern value="%level %thread %logger - %message%newline" /?>
      </layout?>
    </appender?>
    <!-- Set root logger level to DEBUG and its only appender to A1 --?>
    <root?>
      <level value="INFO" /?>
      <appender-ref ref="RollingFile" /?>
    </root?>
  </log4net?>
</configuration?>

그리고 Properties 폴더를 열고, AssemblyInfo.cs 파일을 연다.

이제 맨 아래 줄에다가, 다음 줄을 삽입한다.

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

앞에서 로그 쌓는 로직이 정상적으로 작성되어 있다면, 이제 다시 프로젝트를 실행해보자.

실행 한 뒤에 Build 결과물 폴더를 열어보면 example.log 라는 파일이 생성되는데 그 안에 보면,

Form Init Start와 Form Init End가 보일 것이다.

설정이야 어쨌던 로그가 쌓인다.

 

로그 쌓기 그 방법 2

대부분의 경우는 위의 경우에 다 처리 될 수 있다. (상세 설정은 추가적인 검색을 하면 상세한 설정이 가능하다.)
그런데, 이런 저런 프로젝트에 적용하다가 보니, 이 로그 설정을 동적으로 설정해야 할 경우가 발생했다.

즉 app.config를 이용해서 설정하는 방식으로는 그 설정 내용을 마음대로 주무르기가 무척 힘들다는 사실이다.
예를 들면 로그 파일의 이름이나, 경로 같은 경우다. 경로가 딱 정해진 위치라면 상관 없지만, 프로그램이 실행된 뒤, 동적으로 변경되어야 하는 경우라면 이야기가 많이 달라진다.

예를 들면 Application 관련 설정이 다른 위치에 저장되고, 설정 창을 통해 로그 파일의 위치가 변경되는 경우라면 어떻게 할 것인가? 그럼 매번 app.config를 변경해서 재실행해야 할까?

이런 저런 생각에 동적(코드상)으로 변경하는 방식을 찾아보았고, 그 방법을 정리해 보았다.

 

먼저 동적인 방법으로 설정을 하기 위해서는 log 개체에 대한 구성체계를 가져와야 한다.

	log4net.Repository.Hierarchy.Hierarchy hierarchy = (log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository();
	hierarchy.Configured = true;

 

이제 모든 설정은 hierarchy를 통해서 진행되게 된다.

먼저 제일 중요한 로직이 어디다가 어떻게 쌓을지에 대해서다.
log4net 에서 제공되는 쌓는 방식은 19가지 정도 되지만, 위의 예제도 그렇듯이, 파일로 제공하는 형태로 구성할 예정이다. 방법 1과 동일한 방식으로 쌓으려면 아래와 같은 로직을 통해 쌓는 방식에 대한 클래스를 생성한다.

	log4net.Appender.RollingFileAppender rollingAppender = new log4net.Appender.RollingFileAppender();
	rollingAppender.File = "C:\Temp\Test.log"; // 전체 경로에 생성할 메인 로그 파일 이름
	rollingAppender.AppendToFile = true;
	rollingAppender.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Date;
	rollingAppender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();
	rollingAppender.DatePattern = "_yyyyMMdd\".log\""; // 날짜가 지나간 경우 이전 로그에 붙을 이름 구성
	log4net.Layout.PatternLayout layout = new log4net.Layout.PatternLayout("%date [%property{buildversion}] %-5level %logger - %message%newline");
	rollingAppender.Layout = layout;

여기에 있는 RollongFileAppender는 log 내용을 파일로 쌓는 역할을 제공하는 모듈이다.
이 모듈에 대한 개체를 생성했으면, 이제는 hierarchy에 붙이도록 한다.

	hierarchy.Root.AddAppender(rollingAppender);
	rollingAppender.ActivateOptions();

이제 로그를 쌓는 레벨을 설정한다.

hierarchy.Root.Level = log4net.Core.Level.All;

이 로직을 로그가 쌓이기 전에 한번 실행 할 수 있도록 구성하면 된다. 다음 코드는 위의 부분 부분을 모두 합친 부분이다.

	log4net.Repository.Hierarchy.Hierarchy hierarchy = (log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository();
	hierarchy.Configured = true;

	log4net.Appender.RollingFileAppender rollingAppender = new log4net.Appender.RollingFileAppender();
	rollingAppender.File = "C:\Temp\Test.log"; // 전체 경로에 생성할 메인 로그 파일 이름
	rollingAppender.AppendToFile = true;
	rollingAppender.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Date;
	rollingAppender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();
	rollingAppender.DatePattern = "_yyyyMMdd\".log\""; // 날짜가 지나간 경우 이전 로그에 붙을 이름 구성
	log4net.Layout.PatternLayout layout = new log4net.Layout.PatternLayout("%date [%property{buildversion}] %-5level %logger - %message%newline");
	rollingAppender.Layout = layout;

	hierarchy.Root.AddAppender(rollingAppender);
	rollingAppender.ActivateOptions();
	
	hierarchy.Root.Level = log4net.Core.Level.All;

프로그램 제일 먼저 시작하는 로직에 추가하면 된다. 대개의 경우에는 program.cs 파일내 추가해주면 된다.

        static void Main()
        {
            #region 로그 설정
            log4net.Repository.Hierarchy.Hierarchy hierarchy = (log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository();
            hierarchy.Configured = true;

            log4net.Appender.RollingFileAppender rollingAppender = new log4net.Appender.RollingFileAppender();
            rollingAppender.File = "C:\Temp\Test.log"; // 전체 경로에 생성할 메인 로그 파일 이름
            rollingAppender.AppendToFile = true;
            rollingAppender.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Date;
            rollingAppender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();
            rollingAppender.DatePattern = "_yyyyMMdd\".log\""; // 날짜가 지나간 경우 이전 로그에 붙을 이름 구성
            log4net.Layout.PatternLayout layout = new log4net.Layout.PatternLayout("%date [%property{buildversion}] %-5level %logger - %message%newline");
            rollingAppender.Layout = layout;

            hierarchy.Root.AddAppender(rollingAppender);
            rollingAppender.ActivateOptions();
	
            hierarchy.Root.Level = log4net.Core.Level.All;
            #endregion


            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }

이제 app.config 없이도 log가 쌓이게 된다.

 

정리

이 포스트의 목적은 바로 이 2번째 방법에 따른 방식을 소개하기 위한 글이다.

log4net의 기능의 강력함은 동작 중에 무시할 만큼의 리소스를 소모하면서 강력하게 로그를 쌓는 방식에 있을 것이다. 더욱이 자동으로 파일로 떨구기도 하고, 데이터베이스에 쌓을 수도 있기 때문에, 활용도에서도 우수하다.

개인적으로 현재 프로젝트를 모두 이 log4net 으로 전환하고, 쌓이는 로그를 WinTail(http://www.baremetalsoft.com/wintail/)  이라는 프로그램을 통해서 살펴보고 있다. 동작 중에 발생되는 각종 값에 대한 감시 및 데이터 체크는 모두 이를 통해서 하고 있다. 동적으로 프로그램을 실행하면서 디버깅을 할 때 의외로 편하다.

닷넷 프로그램으로 로깅을 남기는 작업을 해보고 있다면 한번 시도해보심이?

728x90
블로그 이미지

하인도1

[하인드/하인도/인도짱 의 홈페이지] 저만의 공간입니다. 다양한 소재들을 나열하는 아주 단순 무식한 홈페이지 입니다. 다양한 문서 자료도 있겠지만, 저의 푸념들도 있답니다.

OLEDB 개체(Excel, Access) 호환성 높이기

기술자료/.NET 2013. 8. 28. 16:17

요즘 C#을 통해서 Application을 만드는 중인데, 데이터 처리해야 될 내용이 많아, Excel과 Access를 주로 사용하고 있다. 특히 Excel의 경우에는 직접 COM 개체를 활성화 시켜서 Cell 단위까지 찾아 데이터를 가져오는 방법보다,
마치 DB Access 한 것 처럼 OLEDB로 연결해서 가져오는 방법이 가장 효율적이였던 것 같다.

그런데, 문제는 설치 대상 PC안에 오피스 제품이 무엇이 깔렸는지에 따라 이 OLEDB를 사용할 수 있는 것이 전혀 다르다. 특히 2013 이후에는 x64 전용이 있어, 응용 프로그램이 x64에서 동작하게 되면 OLEDB 32bit 버전은 접근이 불가능했다. 그래서 매번 어떤 오피스가 깔렸는지, 32bit, 64bit 구분을 하기에는 너무 로직이 복잡해졌다.

그래서 구글링으로 찾아 다양한 테스트 후 적용했는데 지금은 큰 문제가 없어 보여서 블로깅을 시작한다.

 

문제

오피스 데이터를 DB 처럼 접근하기 위해서는 그에 맞는 Connection String을 구성해야 한다.

MS Access 같은 경우에는,

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\mydatabase.mdb;User Id=admin; Password=;"

라고 쓰고

MS Excel 같은 경우에는

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\MyExcel.xls; Extended Properties="Excel 8.0;HDR=Yes;IMEX=1";"

라고 쓴다.

그런데, 문제는 저 Provider다.
현재 설치되어 있는 오피스 버전에 따라 Microsoft.Jet.OLEDB.4.0 을 쓸수도 있고,
때론 Microsoft.ACE.OLEDB.12.0 라고 쓰기도 하고,
x64 Office 2013의 경우에는 Microsoft.ACE.OLEDB.15.0 라고 해야 동작한다.
그 이유는 설치한 Office 마다 설치되는 OLEDB Provider가 달라서 벌어지는 일이다.

일반적으로 Office 2000, XP, 2003 까지는 Microsoft.Jet.OLEDB.4.0 를,
Office 2007, 2010의 경우에는 Microsoft.ACE.OLEDB.12.0 를
Office 2013의 경우에는 Microsoft.ACE.OLEDB.15.0를 사용하게 된다.

그렇다면 이 Provider가 어떻게 설치되어 있는지 알 수 있을까?
맨 처음, 적용했던 방식은 Registry를 통한 방식이였다.
Registry 내에 설치되어 있는 Provider가 있는지 검색하는 방법인데,
이 방법으로 했을때는 그럭저럭 잘 동작 했다.

그런데, 왠걸... x64로 넘어가자 문제가 발생했다.
분명 해당 Provider는 설치되어 있었지만,
내 프로그램에서 해당 Provider를 찾지 못하는 문제가 발생했다.
즉 x86일 때와 x64일 때 제공되는 OLE DB Provider가 다르다는 사실을 그 때 처음 알았다.

결국 원점으로 돌아왔고, 근본적인 방법을 찾아야 겠다는 생각이 들어 수정하기 시작했다.

 

해결

구글링을 통해서 다양한 웹페이지들을 들락달락해 본 결과 다음과 같은 예제 소스를 볼 수 있었다.
대게의 경우 앞서 언급한 특정 레지스트릐의 값을 통해 등록되어 있는지 여부를 찾는 것이였는데,
애석하게도 실패를 맞봤기 대문에, 실질적인 방법이 필요했다.그러다가 단서를 하나 발견했다.

http://stackoverflow.com/questions/6570066/c-net-get-the-oledb-provider-version

내용을 대충 훝어 본 후, 적절한 예제로 담긴 MSDN 링크를 따라 들어갔다.

http://msdn.microsoft.com/en-us/library/system.data.oledb.oledbenumerator.getelements.aspx

OleDbEnumerator.GetElements 라는 메소드를 사용해보라는 것이였다.
예제의 내용은 아래와 같다.

using System;
using System.Data;
using System.Data.OleDb;

class Program
{
    static void Main()
    {
        OleDbEnumerator enumerator = new OleDbEnumerator();
        DataTable table = enumerator.GetElements();
        DisplayData(table);
        Console.WriteLine("Press any key to continue.");
        Console.ReadKey();
    }

    static void DisplayData(DataTable table)
    {
        foreach (DataRow row in table.Rows)
        {
            foreach (DataColumn col in table.Columns)
            {
                Console.WriteLine(" = ", col.ColumnName, row[col]);
            }
            Console.WriteLine("==================================");
        }
    }
}

즉 OleDbEnumerator 라는 개체를 만들고 그 메소드 중, GetElements 라는 메소드를 호출하면 현재 프로그램 안에서
사용가능한 모든 Provider를 담은 정보를 DataTable 형식으로 돌려주게 된다.

여기서 착안하여, 실제 Provider들 중, 최신 Provider 이름을 추출하도록 했다.

OleDbEnumerator enumerator = new OleDbEnumerator();
DataTable table = enumerator.GetElements();
List aryProviders = new List();
foreach (DataRow row in table.Rows)
{
    aryProviders.Add(row[0].ToString());
}
table.Dispose();
aryProviders.Sort((p, n) => n.CompareTo(p));
string sFoundString = aryProviders.Find(m => m.StartsWith("Microsoft.ACE.OLEDB"));
if (string.IsNullOrEmpty(sFoundString))
    sFoundString = aryProviders.Find(m => m.StartsWith("Microsoft.Jet.OLEDB"));
g_sProviderName = sFoundString;

 

최종적으로 사용되는 값은 g_sProviderName 이라는 값으로, 이 값을 Connection String에 대입하기만 하면 된다.

string sConnectionString = string.Format("Provider=;Data Source=C:\MyExcel.xls; Extended Properties="Excel 8.0; HDR = Yes; IMEX = 1";", g_sProvider);

라고 하면 끝. 그러면 해당 Provider로 연결하게 된다.

Provider 검색하는 코드를 간단하게 설명하자면,  아래와 같다.

  1. 현재 가져올 수 있는 모든 Provider 정보를 DataTable로 가져온다.
  2. 가져온 Provider에서 Provider 이름만 모두 가져와 string array로 만든다.
  3. string array를 이름 별로 Sort 한다. - 최신 버전이 위로 갈 수 있도록 -
  4. 돌면서 최신 버전에 해당하는 것이 있는지 체크하면서 찾으면 해당 이름을 저장한다.
  5. Connection String을 만들 때, 저장한 Provider 이름을 사용한다.

간단하면서도 잘 알지 못하면, 참 어렵게 프로그램을 짤 번했던 기억이 든다.

참고로 Excel의 경우 "xsl" 파일은 Microsoft.Jet.OLEDB.4.0 만으로도 읽을 수 있지만, "xslx" 파일은 반드시 "Microsoft.ACE.OLEDB.12.0" 이상 버전의 Provider를 사용해야만 읽을 수 있다.

즉 위에서 필터링하는 방식에 따라, xlsx 파일을 읽을 수 있는지 없는지를 체크하는 방편이 될 수 있다.

728x90
블로그 이미지

하인도1

[하인드/하인도/인도짱 의 홈페이지] 저만의 공간입니다. 다양한 소재들을 나열하는 아주 단순 무식한 홈페이지 입니다. 다양한 문서 자료도 있겠지만, 저의 푸념들도 있답니다.

아.. 놔...그럼 인터파크 비스킷 교환행사라도 해라!

잡글 2013. 8. 27. 14:10

어느날 인터파크에서 온 메일을 열어 봤는데...

image

뭔가 해서 클릭해봤다.

왠걸... 기존 비스킷은 저만치 멀찍히 치우고, 안드로이드 기반의 패드로 장사한다고 한다.

image

아.. 놔....

거의 30만원돈 주고, 산 기계는 완전히 버려지고, 결국 이런것이나 만들어서 또 판다는.. 이런 불순한 것들.
상도덕이 있는건지.. 없는건지...

기존에 사준 고객들은 그냥 봉이였어?

169,000원 예약 판매라는데... 헐..

기존 고객에 대한 배려는 전혀 없는 그런 상술 펼치는데, 이거 완전히 농락당한 기분이다.

만일 이 기계 혹하신 분이 혹시나 있을까 궁금한데,
애지간 하면,그냥 통신사에서 할부로 패드를 사시고,

그냥 어플깔아서 보시는게 더 나을듯.
어차피 기존 고객에 대한 배려 전혀 없으니 이거 사셔도 결국 퇴물 취급 받고 없어질듯...

728x90
블로그 이미지

하인도1

[하인드/하인도/인도짱 의 홈페이지] 저만의 공간입니다. 다양한 소재들을 나열하는 아주 단순 무식한 홈페이지 입니다. 다양한 문서 자료도 있겠지만, 저의 푸념들도 있답니다.

Alfresco 문서 변환 오류 문제

기술자료/Web 2013. 7. 10. 13:29

Open Source기반의 EDM을 찾다가, 발견한 제품인 Alfresco. Java로 된 솔루션인데, 이미 상용화 서비스를 제공하고 있어서 인지, 제품의 완성도가 상당히 높았다.
그래서 이 Aflresco를 Windows에 설치 한 뒤, 다양하게 사용해 봤는데, 괜찮았다. 그래서 아예 서버를 분리해서 Alfresco 전용 서버를 구축하기로 마음먹고, 성능 향상을 위해 x64기반의 Ubuntu Server 위 에 설치했다.

그리고 현재 잘 사용하고 있다.

 

그런데, 예전에 설치해서 사용할 때는 Office 계열 문서의 경우 자체적으로 PDF로 변환을 해서, 이를 웹상에 바로 노출되었는데, 이게 제대로 동작하지 않고 있다. 즉, 진짜 바이너리 파일 처럼 문서가 계속 Word, Excel 등으로만 뜨고, Preview 화면이 제대로 표시되지 않는 문제가 계속 되었다. 처음에는 변환에 시간이 걸려서 그런가 했는데, 애석하게도 그렇지는 않은 듯 싶다.

 

구글링을 해보니 이런 글(http://www.simonbuckle.com/2007/06/06/converting-to-pdf-with-alfresco/) 이 걸렸다.

" lsof -i | grep 8100 " 라고 입력하면 Office 파일 변환 서비스가 떠 있어야 된다는 의미인데, 애석하게도 실행해본 결과 아무것도 나타나지 않았다. 결국 이 Office 파일 변환 서비스가 제대로 떠있지 않다라는 결론이 나고, 좌절을 맛볼 수 밖에 없었다.

 

마음을 다 잡고 다시 차근 차근 구글링을 시도했고, 이 문제를 해결 하기 위한 답을 찾았다.
이 문제를 해결 하기 위해 아래의 링크들을 참고했다.
https://forums.alfresco.com/forum/end-user-discussions/alfresco-share/cannot-preview-ms-office-files-03122012-1400

https://forums.alfresco.com/forum/installation-upgrades-configuration-integration/configuration/document-preview-broken-42b#p139371

 

문제 현상.

문제가 된 현상은 다음과 같다.


보면 모든 문서들이 단순 아이콘으로만 뜨고 있다. 더욱이 해당 문서 안으로 들어가면, 내용을 보여주는 Preview 화면 조차 없다.

 

그러다가, Tomcat 내부에 있는 catalina.out 이라는 로그 파일을 관찰했고, 문서를 읽을 때마다, 다음과 같은 오류를 뱉는 것을 확인했다.

ERROR [extensions.webscripts.AbstractRuntime] [http-8080-39] Exception from executeScript 
- redirecting to status template error: 02120007
The content node was not specified so the content cannot be streamed to the client:
classpath*:alfresco/templates/webscripts/org/alfresco/repository/thumbnail/thumbnail.get.js org.springframework.extensions.webscripts.WebScriptException: 02120007
The content node was not specified so the content cannot be streamed to the client:
classpath*:alfresco/templates/webscripts/org/alfresco/repository/thumbnail/thumbnail.get.js at org.alfresco.repo.web.scripts.content.StreamContent.execute(StreamContent.java:183) at org.alfresco.repo.web.scripts.RepositoryContainer$2.execute(RepositoryContainer.java:400)

그래서

Exception from executeScript - redirecting to status template error

로 검색을 했고, 위의 문제 해결 링크를 찾았다.

 

 

문제 분석

최초로 찾은 글에서는 몇몇 답변들이 있었지만, 별 의미는 없었다. 하지만, 맨 끝자락에 있는 "TTownsend"라는 분이 글을 남겼고, 그 분이 문제 해결에 대한 Thread를 남겼는데, 그게 결정적이였다. ( Thanks TTownsend! )

 

같은 문제인지 확인해 보려면, /alfresco/libreoffice/scripts Directory로 이동 한뒤, openoffice_ctl.sh 를 실행해 본다. 그러면 콘솔 창에 "openoffice did not start" 라는 메시지가 뜨면 바로 이 해결 방법으로 처리할 수 있는 문제이다.

 

그러면 이제 openoffice_ctl.sh 가 어떻게 실행되는지 확인한다.

 

먼저 openoffice_ctl.sh 파일을 열고 그 안에서 SOFFICE로 시작되는 모든 변수 값을 가져온다.


소스의 맨 윗부분인데, 이 내용을 메모장 같은 곳에 복사해서 각 변수들 값을 조합하여 직접 실행 시킬 수 있는 명령 줄을 만든다.

#!/bin/sh

# Open Office
SOFFICE_PATH="/alfresco/libreoffice/program"
SOFFICE_PORT="8100"
SOFFICEBIN=/alfresco/libreoffice/program/soffice.bin
SOFFICE="$SOFFICEBIN --nofirststartwizard --nologo --headless --accept=socket,host=localhost,port=$SOFFICE_PORT;urp;StarOffice.ServiceManager"
SOFFICE_STATUS=""
이 내용을
/alfresco/libreoffice/program/soffice.bin --nofirststartwizard --nologo --headless --accept=socket,host=localhost,port=8100;urp;StarOffice.ServiceManager
로 만든다.

 

명령줄이 준비되었으면 실행해본다.

root@testserver:/alfresco/libreoffice/scripts# /alfresco/libreoffice/program/soffice.bin --nofirststartwizard --nologo --headless --accept=socket,host=localhost,port=8100;urp;StarOffice.ServiceManager
/alfresco/libreoffice/program/soffice.bin: error while loading shared libraries: libXrender.so.1: cannot open shared object file: No such file or directory
No command 'urp' found, did you mean:
 Command 'unp' from package 'unp' (universe)
 Command 'burp' from package 'burp' (universe)
 Command 'arp' from package 'net-tools' (main)
 Command 'rup' from package 'rstat-client' (universe)
urp: command not found
StarOffice.ServiceManager: command not found
root@docsvr:/alfresco/libreoffice/scripts# apt-file search libXrender.so.1
libxrender1: /usr/lib/x86_64-linux-gnu/libXrender.so.1
libxrender1: /usr/lib/x86_64-linux-gnu/libXrender.so.1.3.0
libxrender1-dbg: /usr/lib/debug/usr/lib/x86_64-linux-gnu/libXrender.so.1.3.0

결론을 내자면, 이 문제의 모든 원인은 바로 Open Office 를 실행하기 위한 필수 라이브러리가 제대로 설치되어 있지 않아 발생되는 문제였다. Open Office 자체가 X11과 같은 X-Windows용 프로그램이다 보니, Linux Server와 최소 설치형태로 제공되는 시스템은 당연하게 X-Windows 라이브러리가 없었고, 그 결과 Open Office 프로그램을 실행할 수 없는 문제가 발생하는 것이다.

 

서버 내에 X-Windows 라이브러리가 없어서 발생되는 문제였으므로, 이 문제를 해결 하려면, 역시 X-Windows를 설치하면 해결 된다. 하지만, 고작 이 Open Office 서비스를 실행하기 위해서 X-Windows를 설치하는 것은 배보다 배꼽이 큰 결과로 봐도 무방한다. GUI 없이 시스템 자원을 확실하게 사용하려고 서버를 깔았는데 말이다.

 

그러므로, 거대한 X-Windows 구성요소 중, Open Office가 실행될 수 있는 최소 필수 라이브러리만 설치하도록 한다.

 

이를 하기 위해서는 준비 작업을 먼저 해야 한다.

 

 

준비 작업

특별히 준비할 것은 없지만, 현재의 문제를 정확히 파악하려면, 패키지 관리 도구를 업데이트 해야 한다.

문제 분석은 현재 설치되어 있는 라이브러리들을 파악해야 한다. 그 라이브러리는 어떤 패키지에 속해 있는지를 알아야 하는데, 그 작업을 하기 위해서는 apt-file 이라는 패키지가 필요하다. (이미 구성되어 있을 수도 있다.)

apt-get install apt-file

apt-file update
먼저 apt-file 패키지를 설치한다. 그리고 apt-file을 업데이트하도록 한다.

그러면 문제의 파일이 어느 라이브러리에 속하는지 알 수 있게 된다.

 

 

해결 방법

앞서 실행해 봤던 명령 줄을 실행한다.

그러면 아래처럼 결과가 나오는데, 그 중 굵게 표시한 부분을 주목하자. libXrender.so.1 이라는 라이브러리를 읽어오는데 문제가 발생했다는 것이다.
/alfresco/libreoffice/program/soffice.bin: error while loading shared libraries: libXrender.so.1: cannot open shared object file: No such file or directory
No command 'urp' found, did you mean:
No command 'urp' found, did you mean:
 Command 'unp' from package 'unp' (universe)
 Command 'burp' from package 'burp' (universe)
 Command 'arp' from package 'net-tools' (main)
 Command 'rup' from package 'rstat-client' (universe)
urp: command not found
StarOffice.ServiceManager: command not found
root@docsvr:/alfresco/libreoffice/scripts# apt-file search libXrender.so.1
libxrender1: /usr/lib/x86_64-linux-gnu/libXrender.so.1
libxrender1: /usr/lib/x86_64-linux-gnu/libXrender.so.1.3.0
libxrender1-dbg: /usr/lib/debug/usr/lib/x86_64-linux-gnu/libXrender.so.1.3.0

문제의 라이브러리가 속한 패키지를 파악한다.

apt-file search libXrender.so.1

라고 입력한다. 그러면 다음과 같은 결과를 돌려준다.

libxrender1: /usr/lib/x86_64-linux-gnu/libXrender.so.1 
ibxrender1: /usr/lib/x86_64-linux-gnu/libXrender.so.1.3.0
libxrender1-dbg: /usr/lib/debug/usr/lib/x86_64-linux-gnu/libXrender.so.1.3.0
결과를 보면 libxrender1 이라는 패키지에 구성된 파일임을 알 수 있다.

 

이 패키지를 다시 설치한다.

 apt-get install libxrender1
그러면 패키지와 연계되어 아직 설치되지 않았던 패키지들이 실행된다.
패키지 목록을 읽는 중입니다... 완료
의존성 트리를 만드는 중입니다
상태 정보를 읽는 중입니다... 완료
다음 새 패키지를 설치할 것입니다:
  libxrender1
0개 업그레이드, 1개 새로 설치, 0개 제거 및 22개 업그레이드 안 함.
20.9 k바이트 아카이브를 받아야 합니다.
이 작업 후 88.1 k바이트의 디스크 공간을 더 사용하게 됩니다.
받기:1 http://kr.archive.ubuntu.com/ubuntu/ raring-updates/main libxrender1 amd64 1:0.9.7-1ubuntu0.13.04.1 [20.9 kB]
내려받기 20.9 k바이트, 소요시간 1초 (13.5 k바이트/초)
Selecting previously unselected package libxrender1:amd64.
(데이터베이스 읽는중 ...현재 83473개의 파일과 디렉터리가 설치되어 있습니다.)
libxrender1:amd64 패키지를 푸는 중입니다 (.../libxrender1_1%3a0.9.7-1ubuntu0.13.04.1_amd64.deb에서) ...
libxrender1:amd64 (1:0.9.7-1ubuntu0.13.04.1) 설정하는 중입니다 ...
libc-bin에 대한 트리거를 처리하는 중입니다 ...
ldconfig deferred processing now taking place

이 작업을 앞에서 Open Office를 실행하기 위한 명령 줄 "/alfresco/libreoffice/program/soffice.bin --nofirststartwizard --nologo --headless --accept=socket,host=localhost,port=8100;urp;StarOffice.ServiceManager"를 실행하면서 오류가 발생하지 않을 때 까지, apt-file search 하고, apt-get install 을 해서 찾는다.

 

그러면 어느 순간부터는 실행 했을 때, 더 이상 입력되지 않고, 무언가가 계속 실행된 상태가 유지되는 것을 볼 수 있다. 필자의 경우 아래와 같이 되고, 실행된 상태로 계속 유지 되었다.

root@testserver:/alfresco/libreoffice/scripts/alfresco/libreoffice/program/soffice.bin --nofirststartwizard --nologo --headless --accept=socket,host=localhost,port=8100;urp;StarOffice.ServiceManager
Fontconfig warning: "/alfresco/libreoffice/share/fonts/truetype/fc_local.conf", line 13: Having multiple  in  isn't supported and may not work as expected

이제 Ctrl + C로 빠져 나오고, ./openoffice_ctl.sh start 명령을 입력한다.

그러면, "./openoffice_ctl.sh : openoffice started at port 8100" 라는 메시지가 나오고 종료된다.

 

그러면 성공!

 

이제 alfresco 서버를 다시 시작하면 정상적으로 동작하는 것을 볼 수 있다.

 



 

결론

X-Windows 라이브러리와 같은 기초 동작 라이브러리만 잘 구성해서 추가해주면 아주 부드럽게 잘 동작한다. 문서 Preview도 잘 되고, 화면도 팍팍 표시된다. 문제는 단순했지만, 역시 잘 모르면, 해결하기 그렇게 쉽지는 않다. 하지만, 전세계를 대상으로 검색해보면, 나와 같은 고민에 빠진 사람들을 쉽게 찾아볼 수 있고, 또, 그 문제를 접근하고, 해결하는 방법들이 잘 나와 있어 얼마나 다행인지 모르겠다. (아직도 NavXX 마수에 빠지신 분은 이 해결 방법 그렇게 쉽게 찾지는 못 할 듯! ㅋ )

 

어쨌던, 이 솔루션 생각보다 훌륭하다. 상당히 안정적이며 빠르다.

물론 설정이나, 구성 방법은 그렇게 쉽지만은 않지만, 그래도 성능 하나 만으로 이 모든 문제를 상쇄할 만큼 훌륭한 제품인 것 같다. 개인적인 문서 / 사진 라이브러리 구축을 위해 사용하고 있지만, 작은 규모의 팀이나, 회사에서도 충분히 활용 할만 하다. ( 아 아직 한글은 지원하지 않는다. 현재 필자가 개인적으로 번역 작업을 해보고 있다. ㅋ )

 

( Alfresco 한글화 구성 사이트 : http://crowdin.net/project/alfresco/ko )

728x90
블로그 이미지

하인도1

[하인드/하인도/인도짱 의 홈페이지] 저만의 공간입니다. 다양한 소재들을 나열하는 아주 단순 무식한 홈페이지 입니다. 다양한 문서 자료도 있겠지만, 저의 푸념들도 있답니다.

MS Access DB 한계

기술자료 2013. 6. 20. 20:11

정확히 하면 MS Access 2003 포맷 기준 MDB의 한계다.

최대 Object의 크기가 2G의 한계를 가지다 보니, 2G를 넘기면 더 이상 데이터 처리를 하지 못한다.

 

완전히 최초 DB에서 아래와 같이 테이블을 하나 만들었을 때 기준으로 본다.

ID(long 4 byte) + id1(long 4 byte) + id2(long 4 byte) + id3(long 4 byte) + datevalue(text * 10 ) + seriesvalue (double 8 byte )....

위 처럼 보았을 때 하나의 레코드를 약, 1~2K 정도로 본다. 최소 단위가 4K니 4K씩 잡아도 된다.

 

여튼, 무한대로 레코드를 넣었는데, 그 결과는...

 

약 2천 3백만 개의 레코드를 넣었더니 결국 무너졌다.

파일 사이즈가 약 2G 정도 되어서 그렇게 된 듯...

 

 

누가 나에게 1억개 되는 레코드를 핸들링 했다고 자랑스럽게 말하길래 진짜? 하는 마음에 돌려봤다. 뭐 1/5 채우고 자빠진 격...

뻥도.. 알고 쳐야지.. 아무한테나 막 내지른다고 완성되는 것은 아닌듯..

 

비정형 DBMS로 하면 모를까, 최소한 MS Access로는 안된다.  쾅!!!!쾅!!!

728x90
블로그 이미지

하인도1

[하인드/하인도/인도짱 의 홈페이지] 저만의 공간입니다. 다양한 소재들을 나열하는 아주 단순 무식한 홈페이지 입니다. 다양한 문서 자료도 있겠지만, 저의 푸념들도 있답니다.

SKT T-Login (와이브로) 쓰면 바보다....

잡글 2013. 6. 10. 12:16

진짜 낚인 기분...

T-Login Wibro를 쓰는데, (SBR-100S) 제대로 안테나가 떠 있는 것을 구경해본 적이 없다.

 

 

저 위치에 불이 들어오는데, 깜빡이면 접속중, 녹색이면 그레이트한 신호, 주황색이면 상태가 영... 붉은색이면 끊길 위험 있음.. 인데... 녹색불은 3달 사용 중 딱 2번 봤고, (그것도 아주 잠시) 대부분은 주황색 아니면 붉은색이다.

 

게다가 내부 홈페이지에 들어가서 와이브로 신호를 보면 아주 가관이다. 안테나가 3개 이상 보는건 정말 레어하고, 대부분은 1개 ~2개가 전부!

 

그래서 지금까지 내가 이 와이브로를 써서 연결해서 데이터를 써본 용량은 1g가 안된다.

(뭐 찾아보니, 5월 16일날 이걸로 다운로드 한번 걸어본 적은 있다. 제대로 데이터가 떨어지는지... ㅋ 1.9G 썼다고 나오는데 ㅎㅎ)

 

3월 02일 ~ 3월 31일 6G (제일 많이 써봄 - 아시아나의 와이브로 안테나 있는 근처에서 해봤음 ㅋ)

4월 01일 ~ 4월 30일 332MB

5월 01일 ~ 5월 31일 1.9G ( 5월 16일만 1.9기가 안테나 근처에서 써보고, 그외는...  ㅋ)

6월 01일 ~ 6월 10일 3M

 

그러니까.. 와이파이 처럼 안테나 근처에서 하는거 아니라면, 쓸 수가 없다.

 

뭐 내 연결 기록은 개인정보니까, 일반 상담원이 접근이 안될테니, 내 말이 진실인지 거짓인지는, 그네들이
알아서 판단하겠지만.... ㅋ

 

 

여튼 지금 있는 곳이 서울시 강서구 등촌돈 인데... 현재 상태가 이렇다.

 

  

 

 

지금 혹시 인터넷 사용량 때문에 고민이여서 와이브로를 고민 중이라면,

일단 SKT는 제외하는게 답이다. 아니면 그냥 요금제를 충분하게 끌어올려서 3G든 4G든, 휴대폰 데이터를 테터링해서 쓰는게 답일듯...

 

와이브로는 이제 사장되고 있는 기술이고, 소규모로 대충 운영 중인 SKT는 일찌감치 끝난듯 싶고,
그나마 KT가 괜찮긴 한데... 앞서 이야기 했듯이 사장되는 기술이다 보니, 조만간 사업 접지 않을까 싶다.

 

 

아쓰... 위약금이 지랠이네;;;;

728x90
블로그 이미지

하인도1

[하인드/하인도/인도짱 의 홈페이지] 저만의 공간입니다. 다양한 소재들을 나열하는 아주 단순 무식한 홈페이지 입니다. 다양한 문서 자료도 있겠지만, 저의 푸념들도 있답니다.

갤럭시S3 3G 최적화

기술자료/모바일 2013. 6. 5. 14:06

 


 


갤럭시 S3를 구입하고, 몇몇 최적화 방법에 대해서 고민을 해봤다.

  갤럭시 S3 LTE에 비해 갤럭시 S3 3G 모델은 메모리가 2G -> 1G로 축소되어 제공되었다. 1G 메모리가 그렇게 작은 크기는 아니지만, 젤리빈에, 삼성 어플에, 심지어 통신사(SKT) 어플까지 얹으니 디폴트로 뜬 용량이 대략 650M를 상회했다.

약간 하이레벨의 프로그램을 돌리거나, 몇가지가 동시에 동작되는 경우 전체적으로 느려지는 건 다반사고, 더욱이 젤리빈으로 넘어가면서 TouchWiz 라는 홈런처 프로그램은 메모리 부족인지는 모르겠지만, 간혹 게임 같은 프로그램을 돌릴 때 저절로 종료까지 되었다.

 

진정한 최적화는 구글 레퍼런스 폰( 넥서스 원, 넥서스S, 갤럭시 넥서스, 넥서스4 등등 )을 사용하는게 답이지만, 애석하게도 난 갤럭시 S3 그것도 3G 버전을 들고 있을 뿐이고.. 최대한 적응하는 수 밖에 없었다.

 

 

그래서 결국 하나씩 손보기 시작했다.

 

단, 최적화에서 다음의 조건을 충족할 수 있도록 했다.

  1. 펌웨어 변경 없이 한다.
  2. 하드웨어 리셋을 하지 않는다.
  3. 최대 500M 이하로 떨어뜨려 2~300M의 공간을 확보한다.

1번 조건은 삼성 정책 때문에 결정했다. 이놈의 삼성에서는 펌업을 하면, 카운트를 하도록 했다. 커스텀 펌웨어를 올린 횟수 만큼 자동으로 카운트가 올라가는데, A/S 받을 때 불이익을 주려고 하는듯 싶다. 물론 이 카운터도 리셋은 가능하지만, 귀차니즘이 한가득한 나로써는 그냥 자연스럽게 커스텀 펌웨어 업데이트를 안하게 만들었다.

 

2번 조건은, 지금까지 설정한, 받아온 이력을 고스란히 남겨보고 싶은 욕심 때문이다. 현재 전화 송수신 이력 부터 모든 문자 메시지까지 지금까지 쭉 사용한 전체 이력 정보 부터 설정 정보까지 그래도 남기고 싶어서다. 물론 A/S를 받거나 하면 홀랑 날려 먹기 충분한 정보지만, 최소한 이 최적화 한다고 날려먹고 싶진 않았다.

 

3번 조건은 최적화 한계치다. 안드로이드 운영체제인 젤리빈도 나름 규모가 있는 운영체제다 보니, 나름 용량을 차지한다. 게다가 1G 라고 했지만, 시스템 영역까지 빼고 나면, 780M 정도... 그렇다면, 최소 500M 안쪽으로 들어가야 200M 정도 확보가 되고, 그래야 게임같은 프로그램을 돌릴때 안정적이지 않을까 싶다.

 

 

이 모든 말을 한마디로 하자면, "순정 최적화" 라고나 할까....

 

 

순정 최적화의 결과물은 아래와 같다.

 

489M 정도. 물론 작업 관리자 뜨면 2~30M가 늘어나긴 하지만, 선방이라고 생각된다.

 

 

 

단, 이 글을 읽고 난 뒤, 최적화를 할 때, 난 왜 안돼???? 라고 반문하기 전 스스로를 살펴봐야 한다.

최적화가 성공적으로 되려면, 불필요한 사항들을 내려서 얻어 낸 것이라는 점이다. 즉, Google Play가 되었던, 어둠의 경로가 되었던, 수만가지의 앱들을 설치하고, 이런 저런 이유로 다양한 앱들을 활성화 시키면 최적화의 의미가 없다.

최적화는 정말 효율적으로 활용하기 위한 방편일 뿐이지, 정답이란 없기 때문이다. 수많은 앱들이 동작시키면서 동시에 최고의 성능을 바란다면, 차라리 최신예 최고급 모델을 사서 쓰는게 답이다.

 

 

불필요한 앱 없애기

먼저 자신이 보유한 앱들을 돌아보면서 불필요한데, 설치되어 있는 앱들은 삭제한다. 간혹 실행도 하지 않으니 상관 없지 않나? 라고 말씀하시는 분들이 있는데, 앱들 중에는 서비스를 등록해서 메모리를 일부 잡아 먹는 일종의 상주형 앱들이 은근히 많다.

 

특히 알림 메시지를 뿌리는 앱들이 대표적인데, 대부분의 게임과, 대부분의 정보성 앱들이 그렇다. 그 외에 상시적으로 데이터를 송/수신 해야 되는 앱들(메일, 실시간 정보 수집 앱 등등) 역시 서비스로 항상 떠 있다.

 

그러므로, 스스로 생각할 때, 1주일 내로 실행된적이 없는 앱들은 과감하게 지운다. 내장 저장소도 비워지지만, 무엇보다 서비스들이 사라지므로 이 또한 큰 효과를 가져온다.

 

여튼 불필요한 앱들은 모두 언인스톨을 하던 삭제를 하던지 해서 확실하게 끝내도록 한다.

 

 

불필요한 기본 앱 없애기

통신사를 거쳐서 판매된 국산 폰들의 최악의 문제점은 사용자가 사용하지도 않을 앱들을 마치 선심 쓰는 양 마구 잡이로 억지로 넣고는 삭제하지도 못하게 만든 점이다. 앞서 말한 불필요한 앱들의 대부분이 바로 이런 앱들이지 않을까 싶다.

 

오른편에 보이는 항목들이 필자 개인적으로 사용하지 않은 앱들로써, 마구 종료시켜버린 앱들이다. ( 삭제가 안됨 )

 

사용중지를 시키는 방법은 설정 -> 애플리케이션 관리 -> 전체 를 선택하면 앱들의 목록이 쭉 나오는데, 그 중 사용 중지 시킬 앱을 클릭해서 들어가서 "강제 중지 -> 사용 안함" 을 클릭한다.

 

 

 

 

홈 런처 변경하기

요즘은 다양한 홈 런처들이 존재한다. 윈도우의 Explorer 같은 것인데, 바탕화면 부터 앱을 실행하기 위한 단계를 나타내는 화면이다.

 

화면 꾸미기 좋아하시는 분들은 이 홈 런처를 이것 저것 깔아서 돌려보는데, 이거 최적화의 큰 걸림돌이다. 게다가, 삼성에서 기본으로 제공하는 TouchWiz는 정말이지 꽝이다 싶다. 화면을 편하게 볼 수 있는 것도 아니면서 앱 관리하는 기능도 불편하고, 게다가, 느리고 무겁기 까지 하다.

 

이것도 걷어내야 하는데, 개인적으로 쓰는 런처가 있으면 1가지만 선택해서 사용하는 것을 권장한다.

 

필자는 작고, 가볍고, 빠른 노바 런처를 사용한다.

 

 

노바 런쳐 개발자들의 머리에 총알이 들어가서 무겁고 쓸데없이 기능만 많은 쓰레기 런쳐로 변신할 수도 있지만, 개인적으로는 현재까지 나온 런처중 가장 가볍고 기본기 충실하다고 생각된다.

 

노바 런처를 설치하고, 기본 런처로 설정해주면 된다.

 

 

정리

운영체제가 업그레이드 되면 당연히 메모리나, CPU, GPU 자원을 더 많이 소모하는 건 어쩔 수 없다. 기능도 기능이고, 기타 자동으로 제공되는 서비스들을 지원하다 보면 필연적일 수 밖에 없다. 하지만, 그렇다고 매번 이 폰을 최신예 기종만을 가져다 쓸수도 없는 노릇이다.

 

진정 최적화 하려면, 운영체제 부터 다이어트 하고, 불필요한 앱들을 청소해야 하는데, 이것을 하려면, 커스텀 펌웨어를 스스로 만들어서 업데이트해야 한다. 하지만, 이 작업을 하기에는 컴파일이라든가, 제품 구성/패키징까지 의외로 난이도가 높다. 차선으로 이런 문제를 안고 있는 사용자들의 커뮤니티를 통해서 만들어진 커스텀 펌웨어를 구하는  방법이 있긴하다. 하지만, 100인 100색이라고, 자신의 입맛에 100% 맞을리 없으니, 이 또한 커스텀 펌웨어를 이것 저것 갈아타는 악순환에 빠질수도 있다. 더욱이 보안 패치 같은 중요한 업데이트에서 누락될 수 있는 문제도 있다.

 

결국 순정으로 돌아가는데, 그러면 다시 최적화 문제로 빠지게 된다.

 

일단, 스스로의 폰에 어느정도 만족하면서 기능을 최대한 활용하는 방법을 고민하다 보면 자연스럽게 최적화를 구성할 수 있을 것이다.

728x90
블로그 이미지

하인도1

[하인드/하인도/인도짱 의 홈페이지] 저만의 공간입니다. 다양한 소재들을 나열하는 아주 단순 무식한 홈페이지 입니다. 다양한 문서 자료도 있겠지만, 저의 푸념들도 있답니다.

DataTable GetChange 사용법

기술자료/.NET 2013. 5. 29. 13:20

요 근래 C#으로 데이터 베이스를 다루는 작업이 늘어가고 있다.

그런데, 단순히 Select / Insert / Update / Delete의 문제는 단순 쿼리 작성으로 해결은 할 수 있었는데,
문제는 변경된 사항만 적용하는 점이다.

 

Select를 해서 가져온 DataTable을 Grid 같은 곳에 DataSource로 붙인 것 까지는 좋은데,
이 Grid에서 데이터를 변경해서 나온 값을 가지고 뭔가 하려고 하니, 도데체 무엇이 변경되었는지를
찾는게 하나의 일이 되버렸다.

 

그렇다고, 전수 검사하는 것도 웃기기도 하고...

 

하지만, 태생이 DB 출신인 DataTable이 변경점 하나 없이 동작한다는 것은 말이 안될 것 같고 해서 이리 저리 사이트 돌아다면서 확인해보니, 역시 있었다.

 

DataTable.GetChanges()

 

이 메소드를 사용하면, DataTable 내의 데이터 변경 점을 모두 가져올 수 있었다.

 

사용방법은 아래와 같다.

 

준비

 

먼저 GetChanges를 호출하는 방법부터 확인하자.

 

이를 위해서 데이터를 준비한다. (여기서의 모든 예제는 SQLite를 사용한다. )

 

 

 

SQLiteConnectionStringBuilder sbConnectionString = new SQLiteConnectionStringBuilder();
sbConnectionString.DataSource = "test.db";
string sConnectionString = sbConnectionString.ToString();
SQLiteConnection conn = new SQLiteConnection(sConnectionString);
conn.Open();

// DB에 테이블을 생성
SQLiteCommand cmd = new SQLiteCommand(conn);
cmd.CommandType = CommandType.Text;
cmd.CommandText = "CREATE TABLE  IF NOT EXISTS T_CATEGORIES ( ID INTEGER PRIMARY KEY NOT NULL, NAME TEXT )";
cmd.ExecuteNonQuery();

// 테이블에 테스트 데이터 추가.
cmd = new SQLiteCommand(conn);
cmd.Transaction = transaction;
for (int i = 0; i < 100; i++)
{
	cmd.CommandType = CommandType.Text;
	cmd.CommandText = "INSERT INTO T_CATEGORIES(NAME) VALUES ( 'Category" + i.ToString() + "');";
	cmd.ExecuteNonQuery();
}

// 테이블의 내용을 Select
DataTable dtResult = new DataTable();
dtResult.AcceptChanges();
cmd = new SQLiteCommand(conn);
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM T_CATEGORIES";

// DataTable에 Select한 내용을 채우기.
SQLiteDataAdapter atapter = new SQLiteDataAdapter();
atapter.SelectCommand = cmd;
atapter.Fill(dtResult);

코드 상에서는 SQLite 개체를 쓰기는 했지만, OleDB가 되었던 MS SQL Server Client가 되었던,
요점은 ConnectionString을 구해와서 Connection을 맺고, Command를 만든 뒤, Adapter 개체를 생성해, DataTable에 Fill 하는 것이다.

 

일단 위의 코드를 사용하면, SQLite를 이용하여 test.db 안에 있는 T_CATEGORIES 라는 테이블의 모든 데이터를 dtResult 라는 곳에 채우는 것이다.

 

일단, dtResult 라는 DataTable을 만들었으면 조작을 시작해보자.

 

 

INSERT

 

데이터를 추가해보자.

DataRow newRow = dtResult.NewRow();
newRow["ID"] = dtResult.Rows.Count;
newRow["NAME"] = "New Category!";
dtResult.Rows.Add(newRow);

데이터 추가 로직은 간단하다. NewRow() 메소드로 DataTable의 Column에 맞게 구성된 DataRow를 확보한 뒤, 그 안에다 적절한 데이터를 넣는다. 그리고 난 뒤, RowCollection 에다 Add 를 한다.

 

이렇게 하면 dtResult라는 DataTable안에 새로운 데이터가 추가된다.

 

그렇다면 변경된 정보는 어떻게 확보할까?

그 때 GetChanges() 라는 메소드를 쓴다. GetChanges() 메소드를 사용하면, 전체 데이터 중에 변경점에 해당하는 값들을 모두 가져올 수 있다.

DataTable dtChanged = dtResult.GetChanges(DataRowState.Added);
foreach (DataRow row in dtChanged.Rows)
{
	if(row.RowState == DataRowState.Added)
	{
		foreach (DataColumn col in dtChanged.Columns)
		{
			Debug.Write(row[col].ToString());
			// 여기서 INSERT 구문을 작성한다.
	        }
		System.Diagnostics.Debug.WriteLine(" ");
	}
}

GetChanges()를 실행할 때, 파라미터를 하나 넣는데, 그 안에 넣는게 바로 DataRowStatus다.
만일 Insert 된 사항이 있으면 Added를 Update된 사항은 Modified, Delete된 사항이 있으면 Deleted를 아예 변경된적이 없는 경우에는 Unchanged를 넣으면 된다. 물론 복합적으로 사용도 된다. "|" 표시를 하면 복합적으로 검색해서 넣어준다.

DataTable dtChanged = dtResult.GetChanges(DataRowState.Added|DataRowState.Deleted| DataRowState.Modified);

변경 점들이 담긴 Table에서 Row들을 하나씩 꺼낸다. 이 정보를 이용해 INSERT 구문을 만들어 DataBase 상에 INSERT 해주면 된다.

 

 

UPDATE

 

INSERT와 매우 유사하다.

다만 틀린 것은 새로 추가된 사항이 아니고, 변경된 점 대비 이전 값이라는 것도 한번 더 체크해야 된다는 점이 다르다.

DataTable dtChanged = dtResult.GetChanges(DataRowState.Modified);
foreach (DataRow row in dtChanged.Rows)
{
    if (row.RowState == DataRowState.Modified)
    {
        object beforevalue = null;
        object aftervalue = null;
        foreach (DataColumn col in dtChanged.Columns)
        {
            beforevalue = row[col, DataRowVersion.Original];
            aftervalue = row[col, DataRowVersion.Current];

            // UPDATE 구문을 작성한다.
        }
        System.Diagnostics.Debug.WriteLine(" ");
    }                                
}

이전 값을 가져올 때는 DataRow의 배열에서 DataRowVersion 값까지 같이 넣어주면 된다. 
이 때, Original을 선택하면 변경 전의 값을 가져온다. 

단, 이 구문은 INSERT된 항목에서는 사용하면 안된다.
INSERT에서는 Original 값이라는 것이 없기 때문이다!

 

 

DELETE

 

이번에는 삭제된 값이다.
삭제된 값을 얻어오는 것도 위의 UPDATE 와 별다르지는 않다.
다만! 현재 값이 존재하지 않는다는게 문제다.

 

만일 아래와 같이 짜게 되면 Exception을 발견하게 된다.

DataTable dtChanged = dtResult.GetChanges(DataRowState.Deleted);
foreach (DataRow row in dtChanged.Rows)
{
    if (row.RowState == DataRowState.Deleted)
    {
        object beforevalue = null;
        object aftervalue = null;
        foreach (DataColumn col in dtChanged.Columns)
        {
            beforevalue = row[col, DataRowVersion.Original];
            aftervalue = row[col];    // 에러 발생!
            aftervalue = row[col, DataRowVersion.Current];    // 에러 발생!

            // DELETE 구문을 작성한다.
        }
        System.Diagnostics.Debug.WriteLine(" ");
    }                                
}

주석 중 "에러 발생!" 이라고 적은 부분이 있는데, row[col] 혹은 row[col, DataRowVersion.Current]를 하게 되면,

"Deleted row information cannot be accessed through the row" 라는 Exception이 발생한다.
이미 삭제했기 때문에, 현재 값이라는 것이 존재하지 않기 때문이다.

 

즉 aftervalue 라는 것 대신 before value(DataRowVersion.Original)을 이용해서 이전 값을 이용해 DELETE 문을 위한 구문을 작성하면 된다.

 

 

 

정리

 

.NET Framework에서는 DataSet(DataTable)을 이용하여 OldDB 개체를 통해 직접 수정하면 데이터베이스 상에서도 반영되게 만들어 줄 수 있다. 즉 DataTable 혹은 DataSet을 Select 등을 활용해 가져온 뒤, DataGrid에서 값을 변경하면, 자동적으로 데이터베이스와 연동해서 바뀐 값이 바로 바로 변경되게 구성할 수 있다는 점이다.

매우 DB 친화적인 것처럼 보일 수 있겠지만, 실제로는 거의 써먹질 못한다.

그 이유 중 하나가 Select를 할 때, 보통 Join을 해서 여러 개의 테이블을 복합적으로 사용하는 경우가 많은데,
이 경우 복합적으로 만들어지는 DataSet(DataTable)은 자동적으로 Update, Insert, Delete를 해줄 수 없다.
결국 개발자가 변경 점에 맞추어 SQL Query문을 생성해서 실행해야 된다는 것이다.

 

이런 변경 점을 즉시 즉시 찾을 수 있다면, 별도로 Dirty Flag를 만들어 변경 점이 있는지 없는지 늘 체크할 필요도 없고,
이전 데이터와 비교한다고 생쑈를 부릴 필요가 없어진다.

( 필자의 프로젝트 수행한 것 중, 무식하게 비교 점을 찾는 프로그램이 있었다. 틈 나면 그 부분도 갈아 엎어야 할 듯...)

728x90
블로그 이미지

하인도1

[하인드/하인도/인도짱 의 홈페이지] 저만의 공간입니다. 다양한 소재들을 나열하는 아주 단순 무식한 홈페이지 입니다. 다양한 문서 자료도 있겠지만, 저의 푸념들도 있답니다.

  • «
  • 1
  • ···
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • ···
  • 156
  • »
250x250

블로그 내에 소스 코드 삽입 이사온 기념 스킨도... RSS 전문 기능 비활성화 관련. 스킨 바꾸어 보았습니다. 서버 파일 정리 좀 했습니다.

«   2025/06   »
일 월 화 수 목 금 토
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

좀 Tutorial windows moss 매뉴얼 지름신 me2photo 인터파크 불만 비스킷 친구 협업 MOSS 2007 e-book me2sms Azure 개발환경 java Buscuit me2dayzm SharePoint 수 것 블로그 twi2me WSS 오류 Google Apps Engine Visual Studio 2010

  • Total :
  • Today :
  • Yesterday :

Copyright © 2015-2025 Socialdev. All Rights Reserved.

Copyright © 2015-2025 Socialdev. All Rights Reserved.

티스토리툴바