원본내용중 누락부분이 있으니 , 전체를 꼼꼼히 보시려면 글 마지막의 레퍼런스를 참고하십시요.


Transitions 으로 작업하기 


D3’s selection.transition  메소드는 DOM 이 바뀔때 애니메이션(변환)을 쉽게 해준다.  예를들어 텍스트 색상을 빨강으로 바꾸기위해서 다음과 같이 body 엘리먼트를 선택하고 스타일 속성을 주는데..

d3.select("body").style("color", "red");

어느정도의 시간동안 변화를 주기위해서는 transition 을 사용한다.

d3.select("body").transition().style("color", "red");


선택할수있는 모든 요소들은 순간적인 변화 대신transition 을 통해 시간을 두고 애니메이션 할수있다. 

Transitions 은 작은 Animation 이다.


Transitions 는 시작과 끝의 2개의 키프레임만 가지고있는 key frame animation 이다. 시작 키 프레임은  일반적으로 DOM 의 현재 상태이고 , 마지막 키 프레임은 당신이 특정한 속성이나 스타일등의 셋이다.

다시 transition 예를 보면 : 

d3.select("body").transition().style("color", "red");

단지 하나의 속성( red ) 만 가지고있는데 , 이것의 스타팅 색깔은 DOM 의  getComputedStyle or getAttribute 를 통해서 가져온후 계산될것이다.


스타팅 색상을 더 명시적으로 선택하려면  transition 을 만들기전에 DOM 을 세팅하면 된다.

d3.select("body")
    .style("color", "green") // make the body green
  .transition()
    .style("color", "red"); // then transition to red

먼저 시작색상을 green 으로 세팅한후에 red 로 변화시켰다.


만약 transition  이 delay 를 가졌다면 시작 색상은 transition 가 시작될때 세팅되야하는데 이때 start event 로부터 listening  을 받아서 처리하면된다.


d3.select("body").transition()
    .delay(750)
    .each("start", function() { d3.select(this).style("color", "green"); })
    .style("color", "red");


더 눈에 뛰는  (explicit approach) 방법은 transition.styleTween 을 사용하는것인데, 이것은 스타팅 값 (색상) 을 DOM 으로 부터 계산하는것을 건너뛴다.


d3.select("body").transition()
    .styleTween("color", function() { return d3.interpolate("green", "red"); });

 

이 마지막 예제는 어떻게 transitions  이 작업하는지에 대한 힌트를 준다.

transition.style 를 사용할때 D3 는  DOM 으로부터 스타팅 값을 가져오고 특정 마지막 값을 보간기(interpolator) 를 생성해서 자동적으로  tween ( 2개 속성 사이의)   스타일을 만든다.

만약 당신이 스타팅 값이나 보간기(interpolator) 를  변경하길 원하면 styleTweenattrTween or tween. 를 사용해라.


Transitions 는 일정시간동안 값을 보간한다.

주어진 시작,마지막 키 프레임으로 어떻게 자연스로운 애니메이션 변환을 수행할수있을까? 

D3 가  어떻게 보간하고 블렌드(blend) 하는지 알아야한다. d3.interpolate 메소드는 적합한 보간기를 각 값의 쌍에 대한 타입을 추론해서 결정한다. D3 는 다음과 같은 공통 타입을 지원한다.

문자  interpolator 는 특별히 유용하다. 그것은 문자들 사이에 포함된 숫자를 발견한다. 

문자 interpolators 는 많은 응용을 가지는데  다음과 같다. interpolating path data (e.g., "M0,0L20,30") 와   CSS font specifications (e.g., "300 12px/100% Helvetica").


항상 문자 보간이 적절한것은 아니다.  시작과 끝의 패스 데이타가 같은 숫자의 컨트롤 포인트를 가지고있지 않다면  더이상 숫자들의 쌍이 의미있지 않다. 대신해서 보간하기 전에  resample the path  것이 필요하다.(또는 advanced shape blending algorithms 적용이 필요함).  마찬가지로 arcs  도  interpolation in polar coordinates 를 요구한다. 각도들이 보간될것이다.


만약 당신이 보간기를 직접 구현하길 원한다면 ,  0~1 사이의 범위를 갖는 함수를 구현해야한다. t = 0 이면 시작 값이고 1 이면 마지막 값이며 , 중간 값에 보간된값들을 리턴해주면된다. 다음은 두 값 사이의 값을 리턴해주는 단순 예제이다.

function interpolateNumber(a, b) {
  return function(t) {
    return a + t * (b - a);
  };
}


보간될수 없는것들 


엘리먼트를 생성하는 보간은 불가능핟. 단지 존재하거나 그렇지 않거나이다. transition를 스케쥴하기위해서 엘리먼트는 반드시 존재해야한다. Selection  메소드는 데이타 조인 (data,enter,exit) 와 연관되며 생성한 엘리먼트(append, insert) 는 오직 selections 상에서 수행가능하다. 

general update pattern 과 함께 transitions  를 사용할때 ,  먼저 enter 와 exit 를 사용한 selections  상에서 데이터 조인을 수행한다. 그리고 나서 각각의 subselection  을  transitions 한다.


var bar = svg.selectAll(".bar")
    .data(data, function(d) { return d.key; });

bar.enter().append("rect")
    .attr("class", "bar")
    … // initialize entering bars

bar.transition()
    … // transition entering + updating bars

bar.exit().transition()
    … // transition exiting bars
    .remove();

For convenience, there are a few exceptions to this rule. You can transition.remove to remove an element at the end of the transition; likewise, transition.text sets the text content at the start of the transition, without interpolating. In the future, transitions may support additional non-interpolatable operations, such as classed and html.

Transition 의 삶

As with concurrent programming, perhaps the trickiest aspect of transitions is that they happen over time rather than instantaneously. The code does not proceed in a single straightforward path, as when the page loads, but as a complex sequence of recurring callbacks. While you can safely ignore this complexity in many cases, you must understand the rules which govern the evaluation of transitions if you want to harness their full power.

Transitions have a four-phase life cycle:

  1. The transition is scheduled.
  2. The transition starts.
  3. The transition runs.
  4. The transition ends.

A transition is scheduled when it is created: when you call selection.transition, you are scheduling a transition. This is also when you call attrstyle, and other transition methods to define the ending key frame. Scheduling happens in your code (for example, in response to the user clicking a button), meaning that the code so far is fully synchronous. This makes it easier to debug, and easier to use ending values that depend on changing global state, such as a scale’s domain.

A transition starts based on its delay, which was specified when the transition was scheduled. If no delay was specified, then the transition starts as soon as possible, which is typically after a few milliseconds. The start event is then dispatched, and the transition initializes its tweens, which may involve retrieving starting values from the DOM and constructing interpolators. Deferring the initialization of tweens to start is necessary because starting values aren’t known until the transition starts. Therefore, if you use attrTweenstyleTween and other tween methods, keep in mind that your code will be evaluated asynchronously when the transition starts!

While the transition runs, its tweens are repeatedly invoked with values of t ranging from 0 to 1. In addition to delay and duration, transitions have easing to control timing. Easing distorts time, such as for slow-in and slow-out. Some easing functions may temporarily give values of t greater than 1 or less than 0; however, the ending time is always exactly 1 so that the ending value is set exactly when the transition ends. A transition ends based on the sum of its delay and duration. When a transition ends, the tweens are invoked a final time with t = 1, and then the end event is dispatched.

#Transitions Are per-Element and Exclusive

Each element transitions independently. When you create a transition from a selection, think of it as a set of transitions, one per element, rather than a single mega-transition running on multiple elements. Different elements can have different delays and duration, and even different easing and tweens. Additionally, transition events are dispatched separately for each element. When you receive an end event for a given element, its transition has ended, but other transitions may still be running on other elements.

For a given element, transitions are exclusive: only one transition can be running on the element at the same time. Starting a new transition on the element stops any transition that is already running. Interrupting a transition on the element has no effect on other elements, and multiple transitions can run concurrently on different elements. While only one transition can be running simultaneously on the element, multiple transitions can be scheduled. For example, you can schedule successive transitions using transition.transition, which creates a new transition whose delay immediately follows the existing transition.

For each element, sequences of transitions only advance forward in time. Transitions are assigned a monotonically-increasing identifier (id) when they are scheduled; each new transition idis greater than the last. When a transition starts on the element, it can only run if the transition isnewer than whatever previously ran on the same element. Thus, starting a new transition implicitly cancels any previous transitions—even if those old transitions have not yet started. This design eliminates the need to cancel transitions explicitly. An excellent illustration of this behavior is thestacked-to-grouped bar transition. This uses two chained transitions: the bars first slide right and narrow; then the bars drop to the baseline. The first transition also has a staggered delay. If you quickly toggle between stacked and grouped, notice the old transition is only interrupted when the new one starts, not when the new one is scheduled.

Similar to how data is bound to an element’s __data__ property, transitions are bound to a__transition__ property. When a transition is first scheduled on an element, this property is created; when the last scheduled transition ends, this property is likewise deleted. Inspecting this property in the console can be useful to debug which transitions are scheduled to run on which elements, as well as to inspect computed tweens and transition timing parameters. Because transitions are bound to elements, you can also reselect elements within a transition and modify tweens or timing. This is most common in conjunction with component-driven transitions, such as the axis component; use post-selection to customize the appearance of elements after invoking the component.

#Additional Reading

This tutorial covered most of the important details in the mechanics of transitions. I omitted an explanation of transition inheritance using transition.each; perhaps I’ll cover that in the future, though see #400 for an example. For more on how transitions should be used (and not just implemented), see my earlier post on object constancy and Heer & Robertson’s excellent paper,“Animated Transitions in Statistical Data Graphics”.





레퍼런스 :

http://bost.ocks.org/mike/transition/

http://blog.visual.ly/creating-animations-and-transitions-with-d3-js

 Mesh Generation 방법 


  (1)Scatter Points를 이용하여 요소망 생성하기 




                                                                            xyz 파일 


                                                                         파일 임포트 

                                                       들로네 삼각화로 메쉬 생성 



(2)Polygon을 이용한 요소망 생성


● 그림과 같이 지형 자료를 바탕으로 polyline을 형성할 수 있다.

● 지형 자료와 polyline의 선 색깔을 구분하기 위해서 polyline의 Display 옵션을 조정할 수 있다.

● Polyline은 마우스 왼쪽 클릭으로 vertex를 만들어 나가며 마우스 오른쪽 버튼을 클릭하면 polyline 만들기를 멈추게 된다.

● 마우스를 vertex에 가까이 가져가게 되면 osnap 기능이 작동하여 작은 사각형이 보이게 된다. 이 상태에서 마우스 왼쪽 클릭을 하여야 만 vertex가 연결된다.

● Polyline을 만든 후에도 polyline을 선택한 후 vertex를 클릭하면 vertex의 위치를 수정할 수 있다.

● 모든 polyline이 연결된 상태에서만 polygon을 만들 수 있다.


                                                     지도를 따라 폴리라인 생성 



                                              폴리라인기반으로 삼각 메쉬 생성


(3) Structured Mesh Generation


본 요소망 생성 방법은 4개 혹은 3개의 polyline를 갖는 polygon에서 각 polyline의 절점을 생성한 후에 요소망을 생성시키는 방법 이다. 4개의 polyline을 갖는 polygon은 삼각, 사각 요소망 둘 다 가능하지만, 3개의 polyline을 갖는 polygon은 삼각형 요소망 만을 형성할 수 있다.









'그래픽스' 카테고리의 다른 글

Ease in / out 보간법 (펌)  (0) 2015.07.22
메쉬 제네레이션 - delaunay triangulation  (0) 2015.07.21

http://www.codeproject.com/Articles/492435/Delaunay-Triangulation-For-Fast-Mesh-Generation  (펌) 



Introduction  

Ten years ago, computing meshes for surfaces in real time for surfaces wasn't realistic, and having a customizable source code module wasn't available either. There are faster versions, but they are large implementations and they are hard to read and modify.  With modern computers and modern languages, not only can simple meshes be generated in real time, the code can be written in ways easy to understand. It is the authors opinion that computational geometry and computer vision are entering a new age where real time processing is realistic for a growing set of problems.  The code is designed to be reused such that a vertex can be used to both generate the mesh, but also be apart of other data structures and track other aspects at a given point.  

To form a surface that can be shaded by a graphics card, the goal is to create a list of vertexes, and a list of triplet indexes of the vertexes that form counter clockwise triangles. Whether it is to visualize a differential equation solved by finite element modeling (FEM) or to view a shape of an object in 3D, the first step is to form the triangle mesh.  Usually selecting a set of points is easy, For simple objects like a cylinder or sphere, the point generation leads directly to triangle generation. Generating a mesh from an arbitrary set of points is where Delaunay's Triangulation proves valuable.  The goal of the code wasn't to compute the ideal triangulation, but instead produce a “good enough” solution for most practical 3D or FEM problems and do so quickly. Thus the code recursively improves the triangulation after adding each point to either a recursion count is reached or it is an ideal Delaunay triangulation. This limits how long a mesh can take to compute and avoids infinite recursion should there be a software bug.

Background

Delaunay's Triangulation is named for Boris Delaunay. The general idea is to form a mesh where each triangle's three points lie on the edge of a circle that doesn't contain any other point. This means given any two adjacent triangle's (quadrilateral) the sum of the angles opposite the dividing line are less than 180 degrees.


Triangle mesh a,b,d and b, c, d don't meet the Delaunay condition. But b,c,a and c,d,a do. This is because angle bcd + dab > 180, but abc+cda < 180. This forces the mesh to have triangles that tend to be as close to evenly spaced as possible.

The Bowyer Watson algorithm iteratively adds a point at a time to a mesh to transform it from one Delaunay mesh to another. The general algorithm works by deleting all triangles whose circumscribed circle contains the new point and reform the mesh. The code provided takes a simpler approach.  

From top to bottom, the triangles are flipped to meet the Delaunay condition with 3 points:

This does the same thing but with seven points. Note how at first the triangles are mostly slivers and other triangles are huge.

 After one level of flipping per insertion the meshing is more regular (below).

After a second round of flipping, the effects of the first flip are then flipped as needed (below).

Design  

Mesh Generation

The Bower-Watson algorithm is a bit complex because:  

  • Adding one point may cause a set of triangles to be deleted, and reformed.
  • Reforming the set at once explores forming many possible triangulations.
  • One must search for the affected triangle's. 
  • There isn't a pattern for adjusting the mesh in an ordered fashion.   

The “hull” based techniques that are also commonly used spiral out from a point and reform the triangulation from the inside out. This approach is nice because it takes an ordered approach to computing and recomputing the mesh. The disadvantage as the software is recomputing the circle for each triangle and sorting through the triangles in real time.  

The code provided takes a hybrid approach that forms a linked list of triangles. Each triangle consists of three vertexes, and each side, there is a pointer to the adjacent triangle (or null). The code has the following advantages:  

  • Each triangle has a link to its neighbors.   
  • Recursion explores outward if a triangle is altered, its neighbors may be affected (no circles).
  • Triangles aren't not generally deleted, they are added or modified.  
  1. Compute the bounding rectangle: 
  2. Note that a->b->c is counter clockwise, so if it had a face rendered by say direct3D, it would face out from the page. Triangle c->b->a is clockwise so it's face is toward the page. As long as the direction is maintained, the start point isn't relevant, so bdc is the same as dcb or cbd. This concept in abstract algebra is often called commutation.

    In memory at this point: 

    Triangle 1 = a,b,c, and side b,c = triangle 2. 

    Triangle 2 = bdc, and c,b = triangle 1.

  3. Find the triangle containing the new point (for example, abc), and replace the old triangle 1 with three new triangles.  

  4. Repair the pointers: 

  5. abe with side be should point to ebc.

    Abe with side ea should point to aec.

    Etc. 

    Then repair those old adjacent triangles that used to point to abc:  bdc side bc used to point to abc, make it point to ebc.

  6. Examine each triangle and it's outward adjacent:. For example bec shares a side with bdc.

  7. Examine the angles across from the adjacent sides. If greater than 180 degrees, flip the adjacent line.

  8. If the triangle is not flipped skip to step 10.  

  9. Reform the old triangles into the new triangles, fix the triangle edges. 

  10. For each triangle and it's adjacent triangle repeat steps 5-8 recursively. 

Triangle Contains a Point

The key to the algorithm is finding the correct triangle to modify.

Classically, a triangle contains a point if it is on the interior side. If a line passes through two points, the line is often expressed as y = mx + b, where m is the slope, and b is the x=0 intercept. The area above the line can be expressed as y > mx+b. So, I a triangle has edge s, r and the other point is t. Then if test point p, is on the same side of the inequality as the point t, then the test point p is on the same side of the line as the other vertex.

This means to compute if a point p is inside, the code compares to see if it's on the same side as the vertex for an edge. That is a lot of computations. Caching the information speeds up the comparison but not enough.  Most triangles don't contain the point, and the point is not anywhere near the triangle. To accelerate the computations, only points that are near the triangle need to be tested using the classical method. The software computes the distance between each vertex and the triangle's center. If the point is not closer than this distance it does not need to be tested.

Acceleration

The triangle objects cache information calculated on demand to form the mesh. When a triangle is "flipped" with it's neighbor, two of it's side's change but two of the points remain. When a vertex moves, it invalidates the existing information about those edges.

For example, the center of a triangle changes if any vertex changes, setting points A, B, C sets the calculated to false, asking for the center calculates it ans sets the flag.

Vertex m_Center;

public Vertex Center
{
    get
    {
        if (m_centerComputed) return m_center;
        m_center = new Vertex(
            (A.X + B.X + C.X) / 3f,
            (A.Y + B.Y + C.Y) / 3f,
            (A.Z + B.Z + C.Z) / 3f);

        float delta = m_center.DeltaSquared(A);
        float tmp = m_center.DeltaSquared(B);
        delta = delta > tmp ? delta : tmp;
        tmp = m_center.DeltaSquared(C);
        delta = delta > tmp ? delta : tmp;
        FarthestFromCenter = delta;
        m_centerComputed = true;

        return m_center;
    }
} 

Once the center is computed the software can reuse this information and it is only then recalculated on demand.

'그래픽스' 카테고리의 다른 글

Ease in / out 보간법 (펌)  (0) 2015.07.22
메쉬 생성 방법 소개  (0) 2015.07.21


사물인터넷을 위한 관제 웹 어플리케이션에서 현재 전기/수도의 사용량을 그래프로 보여주고 싶어서 알아보던중

d3 라이브러리를 알게되어 간단히 적용해보고 (10분 완성) 주석 형식으로 설명을 달아본다. 



0. 적용 모습 





1. d3 라이브러리 include 





2. 웹 페이지에서 그래프가 위치 할만한곳에 div 설정 



3. 웹 페이지 로딩이 끝나면 그래프 시작




4. 그래프 드로잉 부분 


var current_watt_for_graph = 0;


function graphStart(){


    var n = 60,    // x 축 범위를 위한 변수 

   random = d3.random.normal(0, 0), 

   data = d3.range(n).map(random);   // 0~0 으로 x축(60) 범위를 초기화 한다. 


var margin = {top: 20, right: 20, bottom: 20, left: 40},    // 그래프 상하좌우 공백

   width = 500 - margin.left - margin.right,                      // 그래프 x 크기

   height = 280 - margin.top - margin.bottom;                 // 그래프 y 크기 


var x = d3.scale.linear()              // 그래프의 너비에 맞추어 x  축을 0~59로 나눈다.

   .domain([0, n - 1])

   .range([0, width]);


var y = d3.scale.linear()             // 그래프의 높이에 맞추어 0~100으로 나눈다.

   .domain([0, 100])

   .range([height, 0]);


var line = d3.svg.line()               // svg 라인이 설정되는(그려지는) 방법을 알려준다. 

   .x(function(d, i) { return x(i); })

   .y(function(d, i) { return y(d); });

 

   // div id 가 "graph_pane" 인것에 svg 형식의 그래프 그려준다.

var svg = d3.select("#graph_pane").append("svg")    

   .attr("width", width + margin.left + margin.right)       // 너비 설정

   .attr("height", height + margin.top + margin.bottom) // 높이 설정

 .append("g")                                                             //  그룹 "g"  속성  추가 

   .attr("transform", "translate(" + margin.left + "," + margin.top + ")");  // 변환(transform) 속성 설정 


svg.style("fill", "#fff8ee")    // 그래프 색상 설정 


svg.append("defs").append("clipPath")   // clipPath  설정 (보여지길 원하는 사이즈 설정, 이외는 버림) 

   .attr("id", "clip")

 .append("rect")  // rect 설정 

   .attr("width", width)

   .attr("height", height);


svg.append("g")   // x 축에 대한 그룹 엘리먼트 설정 

   .attr("class", "x axis")

   .attr("transform", "translate(0," + y(0) + ")")

   .call(d3.svg.axis().scale(x).orient("bottom"));


svg.append("g")  // y 축에 대한 그룹 엘리먼트 설정 

   .attr("class", "y axis")

   .call(d3.svg.axis().scale(y).orient("left"));


var path = svg.append("g") 

   .attr("clip-path", "url(#clip)")

 .append("path")    // 실제 데이터가 그려질 패스에 대한 설정 

   .datum(data)

   .attr("class", "line")

   .attr("d", line);



  path    // 실제 데이터가 그려질 패스에 대한 스타일 설정 

        .style('stroke-width', 1)

        .style('stroke', 'yellow');


tick();  


function tick() {


 // 새로운 데이터를 뒤에 추가한다. (ajax 를 통해 1초에 한번씩 가장 최신 데이터를 가져온것을 넣어줌)

 data.push(current_watt_for_graph);


 // 라인을 PATH 방식으로 그리자!!!   

 path

     .attr("d", line)

     .attr("transform", null)    // 기존 변환 행렬을 초기화하고  

     .transition()                 // 변환 시작

     .duration(1000)          // 1초동안 애니매이션하게 설정

     .ease("linear")           // ease 보간을 리니어로 처리한다.(https://github.com/mbostock/d3/wiki/Transitions#d3_ease)

     .attr("transform", "translate(" + x(-1) + ",0)")   //  변환행렬 설정   # 패스를 다시 그리는 방식이                                                                                     //  라 좌표를 변환함으로써 출렁거리는것을 막는다. 

     .each("end", tick);    //tick 함수 계속 호출 

 

 //가장 오래된 데이터를 제거한다.

 data.shift();


}

}




5. Ajax 를 통해 서버에서 데이터 가져오기 


var graph_timer = null;

var graph_time_interval = 1000;  // 1 초에 한번 꼴로 데이터 폴링 

function graph_loading()

{

clearInterval(graph_timer);

{

// ajax 로  가장 최근 데이터 1개 가져와서

$.get("cmp_test_watt.jsp", function(data, status){

if (status == "success")

{

console.info(data);

var jsonObj = $.parseJSON(data);

console.info(jsonObj.watt);

current_watt_for_graph = jsonObj.watt;  //  최근 watt 정보 대입

}

else

{

console.info("error");

}

});

}

graph_timer = setInterval(graph_loading, graph_time_interval);

}



SVG 클리핑 패스란 ? 

The clipping path restricts the region to which paint can be applied. Conceptually, any parts of the drawing that lie outside of the region bounded by the currently active clipping path are not drawn.

A clipping path is defined with a clipPath element. A clipping path is used/referenced using the clip-path property.


SVG <g/> 엘리먼트란?  (https://www.dashingd3js.com/svg-group-element-and-d3js)

The SVG Group Element is used to group SVG elements together.

The SVG Group Element is a container that contains all child SVG elements defined inside of it.

The SVG Group Element is defined by <g> and </g>.

The SVG Group Element can be nested inside of other SVG Group Elements:


d3 Transitions

http://bost.ocks.org/mike/transition/




레퍼런스:

https://gist.github.com/mbostock/1642874     





http://opentsdb.net/overview.html를 번역했다. OpenTSDB 는 사물인터넷 분야에서 많이 사용되며, 잘 알려진 에너지 IoT 기업인 OPower (http://blog.opower.com/category/technology/) 에서도 사용중이다.


OpenTSDB 는 타임 시리즈 데몬(
Time Series Daemon (TSD)) 들로 구성된다.(몇몇 커맨드라인 유틸리티셋 포함)
OpenTSDB  상호작용은 TSD 하나 혹은 그 이상이 작동하면서 이루어진다. 각각의  TSD 는 독립적이며 
상태공유없이 돌아가기때문에 여러가지 일들을 하기위해  여러 TSD 들에게 일거리를 던져주는데 아무 문제없다.

각각의 TSD 는 HBase 오픈소스 데이타베이스를 사용하며 타임시리즈데이터를 가져와서 저정한다. HBase 스키마는 저장공간을 줄이기위해 비슷한 타임시리즈를 빠르게 집약하는것에 대해 최적화 되어있다. TSD 유져들은 HBase 에 직접적으로 접근할 필요가 없다. 간단한 텔넷 스타일 프로토콜/HTTP API/ 간단한 빌트인 GUI 등을 경유해서 TSD 와 커뮤니케이션할수있다. 모든 커뮤니케이션들은 동일한 포트상에서 발생한다. (TSD 는 처음 몇바이트를 읽어서 클라이언트의 프로토콜을 이해한다.)




쓰기


OpenTSDB 를 사용하는 첫번째 단계는 TSDs 에 타임시리즈 데이터를 보내는것이다.   여러가지 툴(tools )들이  다양한 소스로부터 데이터를 꺼내서 OpenTSDB 에 넣기위해  존재한다. 만약 당신이 필요한 툴을 찾지 못한다면 직접 스크립트를 짤 필요가 있다.  (e.g. by reading interesting metrics from /proc on Linux, collecting counters from your network gear via SNMP, or other interesting data from your applications, via JMX for instance for Java applications) 그리고 TSDs 중 하나에 데이터 포인트들을 주기적으로 푸시하면 된다.

StumbleUpon 는  tcollector  라 불리는 파이썬 프레임워크를 썼는데(wrote) , Linux 2.6, Apache's HTTPd, MySQL, HBase, memcached, Varnish 등으로 부터 수천가지의 계측데이터를 모으기위해 사용되었다. 
이런 적은 영향(
low-impact)을 주는 프레임워크는 몇가지 쓸만한 컬렉터들을 포함하고, 그 커뮤니티는 꾸준히 그 이상의 기능을  제공한다. OpenTSDB 와 상호작용하는 프레임워크들은  Collectd /  Statsd  / the Coda Hale metrics emitter 를 지원하며 포함한다. OpenTSDB 에서 , 타임시리즈 데이타 포인트는 다음과 같이 구성된다:


  • 계측(Metric) 이름.
  • UNIX 타임스탬프 (seconds or millisecinds since Epoch).
  • 값 (64 bit integer or single-precision floating point value).
  • 태그들의 셋  (key-value 쌍 )  포인트에 해당하는 타임시리즈를  나타낸다.

태그들은 다른 소스들 또한 연계된 엔터티들로 부터 유사한 데이터 포인터들을 구분하기위해 사용된다.  그래서 당신은 쉽게 그들을 개별적으로 또는 그룹으로 나타낼수 있다. 태그는 머신의 이름을 가진 주석된 데이터 포인트들로 구성된다. (머신이 포함된 pool 또는 클러스터의 이름도~) 이것은 당신이  서버의 논리적 풀의 집약상태를 보여주는 데쉬보드 뿐만아니라 추가적으로 서버당 당신의 서비스의 상태를  나타내는 데쉬보드를 쉽게 만들수있게한다.

mysql.bytes_received           1287333217 327810227706             schema=foo host=db1
mysql.bytes_sent                  1287333217 6604859181710           schema=foo host=db1
mysql.bytes_received           1287333232 327812421706             schema=foo host=db1
mysql.bytes_sent                  1287333232 6604901075387           schema=foo host=db1
mysql.bytes_received           1287333321 340899533915             schema=foo host=db2
mysql.bytes_sent                  1287333321 5506469130707           schema=foo host=db2

이 예는 4개의 다른 타임 시리즈에 속한 6개의 데이터포인트를 보여준다. 각각의  계측과 태그의 컴비네이션들은 다른 타임 시리즈를 만들어낸다.  
4개의 타임시리즈 모두는 2개의 계측(
metrics) 은mysql.bytes_received or mysql.bytes_sent중 하나이다.

 데이터 포인트는 최소한 하나의 태그를 가져야하고  계측에 대한 매 타임 시리즈들은 동일한 숫자의 태그(역주: 위의 예는 2개) 를 가져야한다.  데이터 포인트당 6~7개 이상의 태그를 갖는건 추천하지 않는다. 새로운 데이터 포인트와 연계된 비용이 포인트 넘어 태그의 숫자에 지배되기 때문이다.

위의 예의 태그를 가지고서  쉽게 호스트 또는 스키마당 MySQL 의 네트워크 액티비티를 보여주는 그래프나 데쉬보드를 생성할수있을것이다. OpenTSDB 2.0 은 계측의 질과 메타데이터를 추적하는  데이터 포인트들과 함께 non-numeric 주석을 저장할수있게됬다. 


읽기

타임시리즈 데이터는 라인 그래프로 보통 그려질수있다. 그래서 OpenTSDB  는 그래프를 생성기위해  하나 혹은 그 이상의 계측과 태그를 선택하는 빌트인 심플 유저인터페이스를 제공한다.

 HTTP API 는  monitoring frameworks /  dashboards / statistics packages or automation tools 같은 외부  시스템들과  묶여서  OpenTSDB 에서 활용된다. 관련된 툴들을 보기위해  resources 페이지로 가자.  



저는 최근에 사물인터넷 플랫폼에 대해 살펴보는 중에 OSGi 에 대해서 좀 더 관심을 갖게되었습니다. (예전에 이클립스 플러그인 책에서도 쳐음 접하고..) OSGi 는 얼핏 보기에 JNDI 가 제공하는 리소스투명성 및 컴포넌트 베이스 기반 방법론을 합쳐놓은 느낌입니다. 당연하지만 예전부터 많은 컴포넌트 조립 기술(CORBA, COM+) 들이 난립해 왔기 때문에 각각 기술들의 테두리가 분명할리는 없겠지요.  2008년에 쓰여진글이라 좀 됬지만 OSGi 가 궁금하신분은 아래 번역글을 통해서 첫인사를 해보시길 바랍니다. 딱히 OSGi 가 궁금하지 않더라도 옛날얘기 들려주듯이 작성된 IT 선배의 개발 모델 이야기는 충분히 재미있을것입니다. ( 2020년 현재 업데이트:  참고로 자바 9버전의 모듈리티를 이용하면 좀 더 편하게 모듈화를 할 수 있습니다. 그렇다고 OSGi를 대체하진 못합니다. 가장 큰 부분이 자바9 모듈리티는 컴파일 타임에 적용되며, OSGi는 런타임에 설치/업그레이드/제거 까지 할 수 있습니다. 쓰임새에 따라서 달리 사용되거나, 혼용해서 사용 될 수 있을 것 입니다. )



원글 링크 : https://queue.acm.org/detail.cfm?id=1348594

* 번역에 심각한 오역이 있거나, OSGi 에 대한 정보를 공유해주시면 더욱 이 글을 번역한 보람이 있을것입니다. 감사합니다. 

OSGi 가 어떻게 내 삶을 바꾸어 놓았나  

1980년 초반 나는 OOP (object-oriented programming)  를 알게되었으며  홀딱  빠져서 사랑하게 되었다.보통 이런 종류의 사랑은 이 새로운 기술에 투자하기 위해 경영진을 설득시킨다는걸 의미한다. 그리고 무엇보다 중요한것은 쩌는 컨퍼런스에 가볼수있게 된다는 것이다. ㅎㅎ 그래서 나는 상관에게 이 기술의 장미빛 미래에 대한 썰을 풀었다. 어떻게 하루만에 이미 존재하는 클래스들로부터 어플리케이션을 만들수있는지~ 클래스들을 저장소(repository) 로부터 가져와서 그것들을 조합하고 뚝딱똑딱 거리면 새로운 어플리케이션이 쑴풍쑴풍 생겨난다고...

오늘날 우리는  당연히 객체들을 사용한다. 그러나 솔직히 말하자면 1985년에 내가 상관에게 했던 장미빛 이야기는 실제로 구체화 되지 않은거 같다. 객체의 재사용은 결코 사람들이 예견한 수준을 넘지 못했고 여전히 레고 이론은 추구해야 할 경배의 대상이며 다다를수없는 성배와 같다. (역주: 2020년 현재도 요원하다. 다행이 JSON-HTTP가 대세가 됬는데 역시 쉬운게 먹힌다는 걸 방증한다. COM+, 웹서비스,SOA 다 대중성과는 멀다.) 

우리가 필요한것

늦은 90년대, 에릭슨연구소에서 일하는 동안, 나는 레고이론을 탐구할 기회가 생겼다. 홈 오토매이션에 대한 소프트웨어 표준화 작업에 참여하게되었는데 이 작업은 IBM, 에릭슨, 노텔, 사이베이스, 썬, 프랑스 텔레콤, 모토롤라, 필립스등 여러 회사들의 참여하에 시작되었고 그 회사들은 나중에 OSGi 얼라이언스 (오픈 동적 컴포넌트 플랫폼을 진행하기위한) 가 되었다. 우리가 1999년에 직면한 핵심 문제점은 어떻게 여러 임베디드 컴퓨터들 사이에 여러 밴더들의 어플리케이션들이 신뢰성 있게 리소스를 공유하며 함께 작동 할 수 있는지 였다. 간단한 말처럼 들리지만 , 집에는 여러 디바이스들이 연결된 다양한 종류의 네트워크로 이루어져있다. 고로 어플리케이션이 각각 다른 리소스와 기능을 재사용할수있는 모델이 필요하다는것은 처음부터 자명한 일이었다. 

여러 어플리케이션들이 각각 그것의 드라이버들과 라이브러리를 포함하게 강제하는 모델은 알맞지 않다. (예컨데, 오늘날 자바 폰 소프트웨어가 작동하는 방식)  또한 패쇄적인 API 셋도 마찬가지인데 , 타겟 마켓(역자: 스위치,계량기,수많은 센서들) 의 다양성이 너무 크기 때문이다. 더 중요한점은 우리는 이런 어플리케이션들이 서로에 대한 선행지식 없이 어울려지길 바랬던 것이다. 추가적으로 간편한 플러그인 방식이길 바랬다. 새로운 기능 추가를 위해 홈 서버를 내려야만 하는것은 그닥 매력적이지 않다. 1999년에 OSGi 얼라이언스가 출범한것을 상기시켜보면 윈도우95가 주류였는데 기술그룹에서 우리들은 약간의 설정만 바꿔도 PC 가 재부팅되는것에 질려있었다. "No reboot" 는 일찍부터 우리의 경구(mantra)가 되었다.또 다른 경구는 OSGi 얼라이언스 멤버회사들이 크고 작은 범위에서 그들 자신의 방법대로 스펙을 구현 할 수 있다는 것이다. 즉  여러 공급자들로 부터 온 각각의 부분들이 콜라보레이션이 될 수 있어야 한다는 것이다. 

그런 환경에서 보안은 옵션이 아니다. 시작부터 명확해야한다. 보안은 아키텍쳐안에서 구축되어져야한다. 다른 신뢰레벨을 가진 여러 리소스로 부터 어플리케이션을 실행하는 능력은 중요한 요구항목이다. 우리는  퍠쇄 시스템, 벽으로 둘러쌓인 정원, 완전하게 개방적인 시스템 등을 충분히 지원해야한다.

홈서버를 위한 환경선택은 우리가 해야할 첫번째 결정 사항이었다. 이것은 그렇게 힘들지 않았는데 자바는 경쟁자가 없었으며 선 마이크로시스템즈( Object-Oriented 언어로 유명한 ) 는 OSGi 멤버였다. 그래서 자바는 다른 참가자들의 어떤 반대없이 무난히 선택되었다. 자바의 중요한 특징은 VM (가상머신) 아키텍쳐라는것인데 이것은 여러 다른 디바이스들의 스펙에 대한 지원을 쉽게 해주었다. 오늘날  VM 은  다양한언어 (PHP, Scala, Groovy, Ruby, Python, etc.) 를 선택할수있게 해주며 심지어 다양한 하드웨어에서 실행된다. 

객체 얽김 (Entanglement)

저 시기에 객체들은 사용할 만 은 했었지만 그것들의 재사용성은 객체 얽김 문제 때문에 한계가 있었다. 많은 소프트웨어 개발자들은 절망적인 느낌을 받았는데 어떤 경우냐 하면 class A 를 사용할때 , 그것이 라이브러리 B 를 끌어오고, 그것은 라이브러리C 를 필요로하고..괴롭게도 계속된다. 최근 OOP 에서 우리는 커플링에 대한 주의력 없이 캡슐화에 대해 열광하였다. 흥미롭게도 OO 의  전임자는 구조적 프로그래밍이었는데 , 그것의 경구는 "낮은 커플링" "높은 응집력" 이었다. 내가 예상하길 우리는 상속성, 폴리모피즘, 기타 객체지향 신상품들 때문에 매우 바빠질것이라고 봤다.그러나 1998 년에 홈오토매이션 어플리케이션을 위한 자바프레임워크는 클래스들 특성 보다는 커다란 응집도/조밀도 (granularity) 의 크기를 가진 무언가를 요구했었다. 

우리에게 필요한것은 컴포넌트 프레임워크였다. 강건하고 신뢰성있으며 동적으로 컴포넌트들을 관리할수있는 그런 프레임워크 말이다. 우리는 새로운 컴포넌트를 완전히 동적으로 리부팅없이 인스톨 / 시작,멈추기 /  언인스톨 할수있기를 원했다. 만약 컴포넌트 A 가 컴포넌트 B 를 사용한다면 이런 의존성은 관리되야하며 , 컴포넌트가 시작되었을때 예외와 함께 발견되면 안된다. 컴포넌트간에는 서로를 발견할 필요가 있다. 또한 우리는 리부트를 허용하지 않기때문에 그 컴포넌트들은 의존성이 사라질때 탐지를 해야한다. 이런 동적 작동을 하기위해서 우리는 서비스 모델이란 것을 개발했었다. 하나의 컴포넌트가 서비스 객체를 등록할 수 있게하는 것은 또 다른 컴포넌트가 그 서비스를 발견하고 바인딩 할 수 있다는것을 말한다. 만약 서비스가 사라지면 언바인딩도 되면서 말이다. 각각의 서비스는 반드시 그것의 행위를 기술하는 계약서(contract)를 가져야하며 이 아키텍처는 SOA  (service-oriented architecture) 라 불릴수있을것이다. - 이 용어가 인기를 얻기 전 이야기지만 -  오늘날의 대부분 유명한 SOA 와는 대조적으로 OSGi 모델은 웹서비스나 커뮤니케이션 층의 어떤 다른것을 요구하지 않는다. 

OSGi 서비스는 단지  POJO 이다.     

OSGi 스펙들 

썬은 환경을 제공할뿐만아니라, 우리에게 JES (Java Embeded Server) 라고 불리는 구현품을 제공한다. JES 는 자바 가상머신 실행시에 번들 (ZIP/JAR files)의 인스톨/언인스톨을 허용한다. 저것은 VM 은 여러 다른 어플리케이션들 사이에서 공유된다는 것을 말하며  번들은 좀 그저그렇지만 우리는 찾고있던 컴포넌라고 볼수있다. 그리고 개발자로서 품위를 지키기위해 그것을 발전시켜야 한다는 것을 느꼈고 그렇게 했다. - 광범위하게.  우리는 8년을 해왔으며 시계는 여전히 돌아간다. OSGi 스펙은 , 지금 현재 릴리즈 4,  꽤 성숙해있다. 2000년에 인터넷 광풍을 따라서 홈 오토매이션 마켓이 붕괴되었을때에도 (단지 릴리즈1이 나왔을때) ,OSGi 스펙은 전화,자동차,산업자동화등에 채택되었으며, 최근에는 OSGi 기술이 확대시키거나또는 무거운 J2EE 컨테이너 그리고 다른 어플리케이션 서버를 대체할수있는 엔터프라이즈 컴퓨팅 세계에서 꽤 유명하게 되었다. 

시스템 예시 : Idefix 

산업자동화는 내가 OSGi 테크놀러지에서 좋아하는 분야이다. 나는 자바와 임베디드 프로그래밍을 좋아한다. 운수없게도, 소비자 전자회사들은 BOM(원료구입서,재료사양서) 상에서 극단적인 시각을 가지고있으며, C,C++ 같은 언어들에서 더 높게 나오는 소프트웨어 개발 비용을 무시하는 경향이 있다. 이것은 종종 JAVA 꺼져를 의미하며 VM 라이센스는 비용을 지불해야하며 추가적인 CPU , 메모리 요구사항이 있다는것으로 말을 일삼는다.

소량 제작은 소프트웨어 비용을 더 심각하게 만들기 때문에 산업 자동화 마켓에서는 좀 문제이다. 예를 들어서 한 회사가 50십만 유로로 팔리는  Idéfix  라는 산업용 측정 디바이스를 생산한다고 말해보자.  (그것은 가상의 디바이스이지만 정보는 실제 제품/상황 으로부터 수집됬다. 비공개를 원했을뿐..)

Idéfix 는 많은 하드웨어 익스텐션을 가지고있는데, 그것들은 수송라인의 샘플을 위한것이다. 샘플들의 정확한 위치, 특별한 액체 투입, 정밀한 값이 필요한 복잡한 측정등이 필요하다. 명백히 그런 장치는 많은 수량이 팔리지않는다.  고객은 그들의 환경에 딱 맞추기 위해서 확장 커스터마이징을 요구한다.  소프트웨어 아키텍처는 유연성 및 그런 유지비용, 적응성 비용을 낮추기위해 포커싱을 맞추게 된다. 적응성(adaptations ) 이 이런 종류의 시장에 매우 중요한며 또 다른 중요한 요소는 원격관리 이다.

세계 무역시장은 점점 커지고있으며 Idéfix  같은 디바이스는 세계 어디에서나 필요하다. 이런 작은 규모의 판매량은 기술자가 고객 근처에서 원할한 서비스를 해주는것을 어렵게한다. 만약 어떤 문제가 생겼을때 이런 문제는 신뢰성에 큰 타격을 입히는데. 원격 진단 및 소프트웨어 업데이트는 그래서 매우 중요해진다.

Idéfix  는 과거 수년동안 OSGi 스펙을 가진 자바 기반의 방법론에 대한 아이디어를 가진 컨설턴트들과 협동 작업을 해왔다. OSGi 스펙들은 Idéfix 같은 장치들에 대한 요구사항과 굉장히 매치가 잘되는데. 동적 컴포넌트 모델을 제공함으로써 표준 고객 적응성,  하드웨어 아키텍처 확장, 원격관리, 복잡한 측정알고리즘같은 복잡한문제들을 단순화해준다. 플러그향 형태의 시스템이 필요할때 누구한테나 필요하지 않겠는가? 자바가 실시간형태의 디바이스에 사용될수있지만 Idéfix  아케텍처는 하드 리얼타임 코드를 메인 어플리케이션 코드로 부터 분리시켰다. 이 하드 리얼타임 형태는 보조 프로세서에의해 제공되게 하며 , 하드웨어 확장에 그 스스로 임베디드되던가 혹은 플러그인 카드와 함께 제공되게 했다. 하드 리얼타임 부분을 분리시키는것은 복잡하고 치명적인 문제들을 단순화시킬수있었다.

디바이스 드라이버 로딩 

Idéfix 의 디자이너는 1-wire 디바이스를 익스텐션을 구분하기위해 사용했다. 이 간단한 프로토콜은 파워라인같은 동일한 와이어상에서 작동할수있으며, 매우 쌌고 , 간단한 1-wire 디바이스의 네트워크는 지선(ground wire) 과 파워/프로토콜 와이어와 연결되었다. 각각의 1-wire 디바이스는 유니크한 64비트 주소를 가지고있으며 그 주소는 1-wire 프로토콜을 통해 발견되어질수있었다. 일단 익스텐션이 적절히 연결되면 , 1-wire 디바이스 안의 유니크 코드는 안착된 익스텐션의 타입을 감별하기위해 사용 될 수 있었다. 이런것들은 사실 OSGi  디바이스 엑세스 스펙 디자인에 대한 예인데, 이 스펙은 OSGi 동적 서비스 모델을 명쾌히 설명해준다. 

자 더 자세히 살펴보자.

1-wire 버스는 컨트롤러를 요구한다. 그 컨트롤러는 1-wire 디바이스가 네트워크상에 있는지 감지하는데 OSGi 시스템에서 이런 컨트롤러는 프로그램되었으며 그 자체로 번들인 베이스(base) 드라이버라는 것을 통해 관리된다. 베이스 라이버가 새로운 1-wire 디바이스를 감지하면 그것을 OSGi 서비스 레지스터리와 함께 1-wire 디바이스를 나타내는 서비스로 등록한다.OSGi 서비스는 단지 POJO 이며, 서비스 정보에 대한 속성셋을 가지고 있다. 이 경우 하나의 속성은 1-wire (USB,Firewire,RFID,Ethernet, Zigbee, Z-Wave 같은것도 마찬가지) 인 디바이스 카테고리를 나타내는데 또 다른 속성으로는 unique ID 가 있다. 이 경우 1-wire unique code 는 모든 1-wire 칩안에 임베디드되있다. 디바이스 엑세스 서브시스템은 특별한 디바이스 속성을 가지고있는 서비스가 등록되는것을 감지하며 OSGi 프레임워크로 부터 서비스가 등록되면 바로 고지를 받을것이다.

하나 또는 그 이상의 드라이버 위치 서비스들을 통해 번들들의 데이타베이스를 참고하기 위해 속성들을 사용한다. 그 드라이버 위치 서비스는 매칭된 드라이버 로케이션(URLs) 를 리턴하며, 디바이스 엑세스 서브 시스템은 프레임워크 안의 이런 번들들을 로딩할것이다. 물론 그들이 이미 존재한다면 말이다. 이런 드라이버 번들 각각은 드라이버 서비스를 시작할때 등록된다. 이런 드라이버 서비스는 드라이버의 적합성을 따지기위해 사용된다. 가장 적합한것은 드라이버 셀렉터 서비스에 의해 선택되며 그 드라이

버는 그 후에 디바이스 서비스에 붙여서 사용된다.  그 드라이버는 그리고나서 연결된 디바이스의 실질적인 기능을 반영한 새로운 서비스를 등록하는것을 통해 디바이스 서비스를 재구성(refine) 할것이다.

원형은 번들이고 삼각형은 서비스들 인 아래 그림은 각각의 진행사항을 나타낸다. 숫자는 액션의 순서이다.



 역주: 

  0. 어떤 장치(device)가 장착되면 베이스 드라이버가 관리하는 컨트롤러가 그것을 감지한다. 
  1. 그것을  장치 서비스로  등록하면 
  2. 장치 엑세스 번들에서 감지해서
  3. 드라이버 로케이터 서비스를 이용해서 드라이버 db 에서  드라이버 위치를 얻고 
  4. 그 위치를 토대로 드라이버(들)를 인스톨하고 
  5. 드라이버(들)를 찾아서 
  6. 드라이버 셀렉터 서비스를 이용해 통해서 가장 적절한것으로 매칭하고
  7. 드라이버를 장치 서비스에  붙혀서  녀석으로 재구성한다.  


예에서 , 다음 1-wire ID 를 갖는 디바이스는 : 

  67.4B.A7.CD.90.AA.1A.01 

5 센티미터 직경을 가진 샘플 트레이로 정재될수있다. 만약 1-wire 베이스 드라이버가 장착되지 않은 디바이스를 검침하면 적합한 디바이스 서비스는 즉시 등록해제 될것이다. 디바이스 엑세스 번들은 등록해제되었다고 고지받을것이며 , 셈플 트레이 서비스가 등록해제되게 할것이다. 이 예제는 어떻게 이런 번들을 실제 디커플(decoupled) 시키는지 보여주며, 1-wire 리시버 베이스 드라이버는 표준화된 디바이스 엑세스 번들을 인지하지 않거나 어떤 셈플 트레이 서비스에 대한 지식도 가지고있지 않는다.

디바이스 엑세스 번들은 단지 디바이스 속성(properties )에 대해서만 알고있으며 1-wire 컨트롤러의  베이스드라이버에 대한 어떠한 단서도 없으며 . 샘플 트레이에 대한 어떠한 특징도 알수없다.  이런 세가지 컴포넌트가 알고있는 모든것은  단지 서비스들 이다. 샘플 트레이를 위해 다르게 만들지 않았다. 만약 1-wire 컨트롤러 베이스 드라이버 번들이 소프트웨어 업데이터나 샘플 트레이가 제거되었다고 해도 멈추지 않는다.

양쪽 이벤트는 동등하게 다루어지며 이러한 서비스레지스트리를 통한 디커플링 패턴은 OSGi 디자인패턴의 핵심이다.디바이스 드라이버번들을 인스톨링하는것은 꽤나 직설화법처럼 들리는데, 실제적으로 OSGi의 많은 부분에서 모듈레이어에 의해 구성된다.  그것은 VM 안에서 번들을 관리하는 책임이 있다. 중요한 문제는 이러한 번들들이 클래스들과 리소스를 공유한다는것이다. 즉 하나의 번들은 다른 번들로부터 클래스들을 임포트 할수있다는것이다. 컴퓨팅 세상에서 공유는 어렵다..

자바 모듈화 

번들 사이에서 클래스들을 공유하는것은 번들의 ZIP 파일의 일부인 메니페스트에 포함된 OSGi 메타데이터를 통해서 핸들링된다.메니페스트는 헤더네임과 연관된 값들의 리스트이다. 어떻게 공유작업이 이루어지는지 이해하기위해서, 먼저 자바패키지를 이해해야하는데 자바 패키지는 그저 클래스들과 리소스들을 가진 디렉토리이다. 클래스들은 다른 패키지들 끼리 동일한 이름을 각각 가질수있다. OSGi 시스템에서 패키지는 다른 번들로 익스포트되거나 다른 번들로부터 임포트되는거나 완전히 감추어지는데 각 익스포트된 패키지는 버전을 가지며 , 임포트는 일정한 버전들을 가지고 올수있다. 다른 번들로 부터 패키지들을 감출수있는것은 장점이 있는데 ,그  패키지들안의 클래스들이 나중에 새 버전으로 릴리즈할때 그것을 사용하는  클라이언트에게 영향을 미치지 않고 수정될수있다는것이다.  이것은 no import, no export , no hiding of classes 인 곳의  Plain Java 와는 근본적으로  다른점이다. OSGi 시스템에서 각각의 번들은 자신의 클래스 공간을 가지는데, 그 공간은 클래스들의 일관적인(consistent) 셋으로 구성된다.  일관성(Consistency) 의 의미는 같은 이름을 가진 클래스들은 항등적이며 (identical) 일관적이지 않은 클래스들에 닿을수없다는것이다. (classes with the same name are identical and cannot reach classes that are not consistent. ) 

다른 번들들은 다른 클래스 공간에 속할수있다. 그러나 동시적으로 같은 VM 안의 존재하기위해  같은 어플리케이션이나 라이브러리의  다른 버전을 따른다 (허용한다) . OSGi 프레임워크는 자동적으로 다른 클래스 공간들안의 번들들을 분리한다. 그래서 그들은 충돌하지 않게된다. 클래스 공간을 관리하는 동안에 익스포트들을 위해 임포트들을 풀어내는것(Resolving) 은 매우 어려운 문제인데 각 가능한 케이스에서 해결책을 보장할수가 없다. 이 리졸빙 알고리즘은 OSGi 스펙에서  구현자들이  혁신적인 해결책을 찾기위해 자유롭게 연구중인 아주 자그마한 영역중에  하나이다.    운좋게도 번들 개발자들은 완전히 이런 어려운 문제로부터 보호받고있다. 이런 모든 복잡성은 쉽게 사용가능한 API 로부터 감춰져있으며 , 우리의 예제에서는 드라이버 번들은 오직  OSGi 프레임워크이 적합한 번들을 찾을수있게하는  URL 을 제공할뿐이다. 그 번들은 파일 시스템, 웹 서버, 데이타베이스 및 Java URL 을 가진 어떤 위치에나 거주지를 마련할수있게된다. 번들은 ZIP 파일들이고 , 그러므로 자바코드 이상의 것을  포함할수있다. 내포적 (introspective 역주: 스스로를 설명할수있는 )이고 중요한 시간에 이벤트를 발생시키는  잘 정의된 라이프싸이클와 함께 그것을 사용하라너는 단지 디바이스를 위한 자바 코드가 아니라 컨텐트를 가져다주기위한 시스템을 가지고있다.  Idéfix 에서 보조프로세서위에서 돌아가기위해 필요한 코드를 예로들어서 갖는다. 이런 코드를 인스톨링하는 일은 어쩌면 디바이스 드라이버의 몫이 될수있는데 그러나 모든 다른 디바이스에게 매우 유사한 코드가 될수있다. 또한 신뢰성의 이유로서 , 또 다른 번들이 모든 보조프로세서들을 위해 이 코드를 관리한다면 더 나을것이다.

그러므로 Idéfix  장치는 인스톨이 필요할때  특별한 디렉토리에서 찾을수있는 번들을 가진다.(고지는 라이프 사이클 이벤트 동안 보내어진다)  만약 이 디렉토리가 보조프로세서를 위해  코드 이미지를 포함한다면, 이 번들은 자동적으로 그것을 인스톨할것이다. 만약 번들이 업데이트되었다면, 그 보조프로세서상의 이미지는 따라서 업데이트 될것이다.  만약 번들이 언인스톨되면, 그 코드는 보조프로세서(auxiliary processor) 로부터 제거될것이다. 또 다른것에 번들의 (관리되는) 라이프 사이클을 매칭하는것은 매우 유명한데 extenders 이라는 이름을 가지고있다. Extenders  는  help resources, install database tables, provide Web services 이런것들을 등록하기위해 사용된다. 

디폴트 JAR 매니페스트파일 (역자추가: 오라클참조)

JAR file 을 만들때, 자동적으로 디폴트 매니패스트 파일을 만들어지는데 . 오직 하나가 존재할수있다.

META-INF/MANIFEST.MF

디폴트 매니패스트 파일은 간단하며 다음과 같다.

Manifest-Version: 1.0

Created-By: 1.7.0_06 (Oracle Corporation)

매니페스트는  "header: value" 와 같이 헤더의 이름과 값은  콜론으로 분리되며 추가적으로 다양한 정보가 들어갈수있다.

리플렉션과 인트로스펙션 (역자추가: 위키참조)

컴퓨터 과학에서, 반영(Reflection)은 컴퓨터 프로그램에서 런타임 시점에 사용되는 자신의 구조와 행위를 관리(type introspection)하고 수정할 수 있는 프로세스를 의미한다. “type introspection”은 객체 지향 프로그램언어에서 런타임에 객체의 형(type)을 결정할 수 있는 능력을 의미한다.

많은 컴퓨터 아키텍처에서, 프로그램 명령은 데이터와 같이 메모리에 적재되므로, 명령과 데이터 사이의 구분은 단지 컴퓨터와 프로그램 언어에 의하여 어떻게 정보가 처리되느냐의 문제이다. 일반적으로, 명령은 실행되고, 데이터는 (명령의 자료로서) 처리된다. 그렇지만, 어떤 언어에서는, 프로그램은 명령 역시 데이터와 같은 방식으로 처리 할 수 있기 때문에, Reflective 수정이 가능하게 된다. 가장 일반적으로 반영은 스몰토크, 스크립트 언어와 같이 높은 수준의 가상 머신프로그램 언어에서 주로 많이 사용되고, 자바, C 언어와 같이 선언적이거나 정적 형식의 프로그램 언어에서는 드물게 사용된다.

서비스 지향 비지니스 모델 

산업에서 복잡한 제품(products) 을 만들기위한 분명한 트랜드는 제품(products)을 파는것으로 부터 멀어지고 대신해서 서비스를 판매하는데 촛점을 맞추라는것이다. 예를들어서 GE 는 비행기를 위한 엔진 (products) 을 파는것을 멈추고 대신 오늘날에는 그들에게 서비스로서 추력 (thrust) 를 판매한다.  또다른 예는 하이델베르그(Heidelberg) 로서 프린팅 프레스 제조업인 이 회사는 지금 복사 프린트로 돈을 벌고있다. 이런 비지니스 서비스 모델은 그렇게 다양하지 않은 스킬들을 요구하기때문에  고객을 더 기밀(agile)하게 만든다. 그리고 제조업의 손에는 더욱 큰  책임감과  여러 전문기술들을 던저 버린다.Idéfix  제조품은 서비스 베이스 비지니스 환경에서 사용되길 의도했었다. 분명히 , 원격 관리와 함께한 번들 모델은 좋은 매칭을 가진다.  그 장치들은 결국 세상 어디에나 있을것이기 때문이다. 성공을 위한 이런 비지니스 서비스 모델에 대한 강한 요구사항이 있지만 고객의  공장(토지)에 설치된 그 장치들은 보안(고정)되있고 쉽게 조작할수없다. (secure and tamper proof. )

만약 고객이 counters  를 리셋할수있거나 , 비 인가된  방식으로 장치를 사용할수있다면 , 그 제조회사는 돈을 읽게되겠지..결국 보안 모델은 매우 중요하다. OSGi 보안모델은 번들과 함께 시작한다. 번들은 X.509 증명서를  사용한 인증을 위해 공용키/개인키를 사용하여 서명될수있다. 우리가 작은 별도의 룰을 세팅해야할지라도 , 이것은 자바에 의해 제공되는 기본적인 모델이다. 자바 보안 모델의 중요한 문제는 모델이 높은 복잡도(fine granularity)를 가지고있기때문에 만들어지는 설정관리 문제이다. 

( 역주: Granularity에는 Coarse-Grained와 Fine-Grained라는 개념이 있다. 이는 서로 반대되는 개념으로써 전자는 보다 더 뭉쳐져있는 정도를 말하고 후자는 보다 잘게 잘게 쪼개져있음을 의미한다.자바 시큐리티를 관리하기 시도하는것은 매우 어렵다.  

많은 시스템들이 끝내 2가지 정적 레벨을 가지게되었는데 "보안하지 않거나, 모두 허용  ㅡ.ㅡ;; "OSGi 는  보안 매니지먼트를 번들기반의 깔쌈한 모델을 제공하여 간소화한다. 각 번들은 승인(permission) 셋을 가지고있고 그것은 컨디셔널 승인 관리자 서비스가 사뿐사뿐 돌아다니며 바꿀수있다. 게다가 각 번들은 허가설정(permission) 파일을 포함하며 번들이 환경으로부터 얻은 승인설정을 더욱더 제한할수있다. 그 아이디어는 서명자는 그들이 사인하기전에 번들의 보안스코프를 확인할수있게하는것이다. 이 모델은 보안 퍼미션들의 관리가 복잡한 문제일지라도 그것을  다루는것을 꽤 단순화해준다. 

OSGi and Open Source

Another advantage that made Idéfix easy to sell to the software developers is Eclipse, a free open source development environment. The developers at Eclipse had originally created their own plug-in model, but in 2003 they were looking for a more dynamic model. After evaluating several modularity systems, OSGi technology came out on top (OK, it might have helped that I was part of the team). The Eclipse team then did an amazing job of open-heart surgery by removing the old plug-in engine, replacing it with a brand new framework compatible with OSGi, and creating a compatibility layer that made all existing plug-ins compatible with the new system. To top it off, Eclipse provided an excellent environment in which to develop bundles. Though it is not a key requirement, there is definitely synergy if bundles for a device can be developed and tested in the same environment as your desktop. This is a key advantage of OSGi and why we sometimes call it universal middleware. Properly designed bundles run almost anywhere.

Idéfix’s architecture allowed for a lot of use of open source projects. For the OSGi framework, Idéfix chose Apache Felix, one of the key open source OSGi implementations. It also used bundles from Knopflerfish (an open source project with commercial backing) and Equinox (the Eclipse OSGi implementation). These projects implement most of the service specifications of OSGi release 4. Idéfix could also have chosen from one of the commercial implementations available from companies such as Makewave, ProSyst, IBM, and others.

Unfortunately, not all Java-based open source projects provide the right metadata for OSGi frameworks, even though the necessary headers are quite easy to add when a project is built with make, ant, maven, or the bnd tool. These headers do not cause any overhead or problems when the JARs (Java archive files) are used without OSGi. We hope that the increasing adoption rate of OSGi in our industry will help improve this situation dramatically in the next year. In the meantime, there are two projects, one in Eclipse and one in Apache Felix, that provide bundle-ized JARs for many open source software projects.


Application Programming Models

One of the great software insights of the past decade is the concept of a POJO. POJO-style programming means that we write Java code that is coupled to the Java environment but not to a specific container. We have learned the hard way that coupling our application logic to a framework is a bad idea because it locks us in. We always need some code that bridges our container with the POJO, however. This code injects any dependencies into the POJO so it can remain oblivious to where those dependencies come from. Though the OSGi framework is lightweight, it is also some kind of container and the same rules therefore apply.

Several application frameworks based on dependency injection have been developed to allow POJO programming in an OSGi environment. These frameworks hide the complexity of the dynamic dependencies, add extra layers such as transactions and remoting transparently, and simplify programming of the application logic.

The OSGi Alliance specified the declarative services application model for the release 4 service platform. The declarative services model is a small but effective dependency injection model based on the OSGi service model. Apache Felix took an interesting approach with iPOJO. This model reduces many programming chores by analyzing the bytecodes and inferring the intentions for many common tasks.

The best-known application programming model for OSGi is Spring. SpringSource, the Spring guardian, extended the Spring bean configuration model to connect to the dynamic OSGi services. This turned out to work extremely well because Spring and OSGi had little overlap and were extremely complementary. Spring-OSGi is highly popular in the enterprise software market at the moment. In the near future, the SCA (Service Component Architecture), an effort from OASIS with all the major players in the enterprise software market, will map SCA to OSGi, a promising combination.

Five different programming models, and counting, is quite a lot for a technology such as OSGi, because the collaboration among these models could be severely impaired. All these application models, however, use the OSGi service registry at the base. Through the registry, a Spring-OSGi application works seamlessly with an iPOJO application or a declarative services application. Developers can therefore choose which model provides the best solution for them but still reuse components written in other application models.

Reflecting

The future of the OSGi technology looks pretty rosy. It is a mature standard, proven in many markets, has many implementations, and has shown to scale well. It provides the foundation for a true universal middleware standard that could have a huge impact in our industry, if we can explain the technology to a wider audience.

We have done the groundwork, but we are far from finished. We need more companies that are willing to take the standard in different directions so we can get closer to fulfilling the promises of the Lego hypothesis: a model where components are wired together to create advanced applications. On that day, I can finally say that my original pitch to my manager has come true.

PETER KRIENS is the OSGi director of technology and CEO of aQute. He has worked as consultant for a large number of international companies introducing object-oriented techniques. In 1994 he moved to Sweden to work for Ericsson. In 2001, he was hired part-time by OSGi to act as its technical director. His responsibilities include editing the specifications and serving as the OSGi evangelist.



JNDI 는 자바 네이밍 / 디렉토리 인터페이스인데 J2EE 의 가장 중요한 스펙중하나이다.

많은 전문가들은 JNDI 의 역할과 중요성을 이해하지 못하고서는 진정한 J2EE EJB 를 알고있다고 말할수없다고 한다.

과연 JNDI 의 역할은 멀까?

JNDI 의 역할을 이해하기위해  "JNDI 가 없다면 어떻게 해야하는지"  를 먼저 보고  JNDI 를 사용하는것에 대해 살펴보자. 

마지막으로 JNDI 의 실행모습과 환경설정등에 대해 알아보자.


* 구체적인 사용방법은 다른 블로그를  참고하도록하자. 




1. JNDI 왜  사용하나? 


JNDI 의 역할을 이해하기위해  "JNDI 가 없다면 어떻게 해야하는지"  를 먼저 보고  JNDI 를 사용하는것에 대해 살펴보자. 


JNDI 없이 


MySQL 데이타베이스에 접근하기위한 어플리케이션을 개발할때,  MySQL JDBC 드라이버 클래스를  참조하기위해 

해당되는 JDBC URL 를 사용하는데 대략 다음과 같다.


Java code 


Connection conn = null; 
try { 
    Class.forName ("com.mysql.jdbc.Driver" , true, Thread.currentThread (). getContextClassLoader ()); 
    conn = DriverManager.getConnection ("jdbc: mysql :/ / MyDBServer? user = qingfeng & password = mingyue"); 

    ...... 
    conn.close (); 
} 
.....


이것은 전통적인 접근방법이며 , 다른 언어개발자들에게도 일반적인 방법이다. 이 접근법은 일반적으로 작은규모의 개발

 프로세스에 적합하며  자바언어에 익숙하기만하면 어플리케이션을 금방 만들수있는 장점이 있다. 


 

JNDI 식 접근 


1. 데이타베이스 서버이름 MYDBSERVER/사용자이름,비밀번호/ 바꿀필요가 있을때라든지 JDBC URL 을 수정할필요가 있을때

2. 데이타베이스가 다른것(DB2, Oracle등) 으로 바뀔수있을때

3. JDBC 설정이 바뀔필요가 있을때 (커넥션 풀 파라미터등등) 


해결책 : 

프로그래머는 데이타베이스 백그라운드에서의 특별한 세팅에 대해 신경쓰게 하고 싶지 않다. 데이타베이스 관리자가 

진두지휘하고 프로그래머는 그냥 가져다 쓰게하고싶다.


그럴때 JNDI 가 있다.


우선 J2EE 컨테이너에 JNDI 파라미터를 설정하고, 데이타소스등을 정의한다. JBoss 에서의 예를 보자


<? Xml version = "1.0" encoding = "UTF-8"?> 
<datasources> 
<local-tx-datasource> 
<jndi-name> MySqlDS </ jndi-name> 
<connection-url> jdbc: mysql :/ / localhost: 3306/lw </ connection-url> 
<driver-class> com.mysql.jdbc.Driver </ driver-class> 
<user-name> root </ user-name> 
<password> rootpassword </ password> 
<exception-sorter-class-name> org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter </ exception-sorter-class-name> 
<metadata> 
<type-mapping> mySQL </ type-mapping> 
</ Metadata> 
</ Local-tx-datasource> 
</ Datasources>


2 . 소스에서 사용하기 


Java code 
Connection conn = null; 
try { 
    Context ctx = new InitialContext (); 
    Object datasourceRef = ctx.lookup ("java: MySqlDS"); / / reference data source 
    DataSource ds = (Datasource) datasourceRef; 
    conn = ds.getConnection (); 

...... 
c.close (); 
} 
.....




시스템에 대해 배포후에 , 만약 데이타베이스 관련된 파라미터가 바뀔때 오직 mysql-ds.xml 설정만 바꿔주면 된다.

소스코드를 바꿀필요없이  아마 그것만 하는 관리(개발)자를 두면 그사람이 알아서 회사(제품)방침에 따라서 조작 할것이다.

JNDI 는 프로그램과 데이타베이스간에 타이트하게 묶여있는 커플링을 피하게 해주며, 쉽게 설정,배포하게해준다.


3. 관련 이미지 




위의 예는 DB 에 접근하기위한 방법에 대한 예이지만, 모든 리소스들에 대해서도 투명화하기위하면 사용할만하겠다. 

예를 들어서  밴더별 컴포넌트, 디바이스 드라이버, 환경설정등등..

근데 요즘 OSGi 도 살펴보는중인데 OSGi 는 JNDI 의 특성(위치투명성)과 기존 컴포넌트베이스개발방법론이 합쳐진거

같은 느낌을 받았다.



2. JNDI 모습들과 환경설정에 관하여




환경 설정에 관한 이야기들 


웹로직/톰캣 서버가 부팅시에 JNDI 객체를 등록합니다.

JNDI 서버의 실제 구현 기능은 각 Application Server의 Vendor (톰캣, 웹로직같은) 가 제공함

JNDI 서버 단독실행 가능함 : http://meri-stuff.blogspot.kr/2012/01/running-jndi-and-jpa-without-j2ee.html

간단한 JNDI 서버 : https://code.google.com/p/osjava/wiki/SimpleJNDI

어떻게 원격 JNDI 서버에 접속하나? : http://stackoverflow.com/questions/15272467/how-to-lookup-remote-jndi







레퍼런스:

http://www.databaseskill.com/216815/





이번 연재에서는 이전에 만들었던 소스에 아래와 같은 기능을 추가할것이다.

HTTPS  기능 

https 는 http 에 SSL 기능을 추가한것인데 ,  HTTP 는 문자를 가지고 누가 엿보기가 쉽다. 따라서 

통신하는데 해당 문자를 암호화해주며, 암호화 하기위한 키에 대해 안전성을 보장해주는 기술이 들어가있다. 

SSL : https://wiki.kldp.org/HOWTO/html/SSL-Certificates-HOWTO/x70.html

1. security-context.xml 파일에 설정 추가 


<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"

  xmlns:beans="http://www.springframework.org/schema/beans"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd

           http://www.springframework.org/schema/security

           http://www.springframework.org/schema/security/spring-security-3.2.xsd">

            

<http auto-config='true'  use-expressions="true">      

<intercept-url pattern="/login" access="permitAll" />   

<intercept-url pattern="/resources/**" access="permitAll" />  

<intercept-url pattern="/**" access="hasRole('ROLE_USER')"  requires-channel="https" />  

<form-login login-page="/login"                    

default-target-url="/monitering"          

username-parameter="username"        

password-parameter="password"          

authentication-failure-url="/login?error" 

always-use-default-target='true'           

/> 

<logout invalidate-session="true"   

     delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"  

logout-success-url="/login?logout" /> 

<remember-me key="wmoskey" token-validity-seconds="2419200"/> <!-- 4 weeks -->

<!-- enable csrf protection -->

<csrf/> 

</http> 


        <authentication-manager>

    <authentication-provider user-service-ref="memberService"/> 

</authentication-manager>

<beans:bean id="memberService" class="com.company.wmos.auth.MemberService"> 

    </beans:bean>

   

</beans:beans>

 

설명)

requires-channel 를 추가하였다. (한줄이면됨)

설정은 위에 한줄이면 되며 , 톰캣에 HTTPS 설정을 하면되는데 아래 싸이트를 참고하자

http://visu4l.tistory.com/419


싸이트 내용중에 참고로 국가코드는 KR 을 넣어주면 되며, 
아래에서 명령에서 trustcscerts  들은 모두 오타이다. trustcacerts 로 바꿔주자.


keytool -import -alias Root -trustcscerts -file TrialRoot.pem -keystore testserver


keytool -import -alias Intermediate -trustcscerts -file TrialIntermediate.pem -keystore testserver


keytool -import -alias testserver -trustcscerts -file cert.pem -keystore testserver





HTTPS 설정을 위한 다른 방법  ( 번역글 ) 

http://www.javacodegeeks.com/2012/12/securing-your-tomcat-app-with-ssl-and-spring-security.html\

SSL 과 Spring Security 를 가지고 톰캣 웹어플리케이션을 보호해보자.

만약 나의 마지막 블로그를 읽었다면 ten things that you can do with Spring Security.  를 알게되었을것이다.
그러나 스프링 시큐리티를 시작하기 전에 해야할것은 웹어플리케이션이 HTTPS 를 지원해야한다는것인데, 그것은
비밀번호같은것을 평문으로 인터넷상에 돌아다니는것을 막아줄것이다.  
자 HTTPS 설정을 시작해볼까? 

1.Key Store 만들기

처음으로 할것은 인증서를 포함한 사설 키스토어 를 만들것것이다.  그것을 생성할 가장 간단한 방법은 

자바 keytool 유틸리티를 사용하는것이다. 자바SDK 설치했으면 /bin 디렉토리안에 있을것이다.

keytool -genkey -alias MyKeyAlias -keyalg RSA -keystore /Users/Roger/tmp/roger.keystore


위의 명령어에서 

  • -alias 키에 대한 유니크한 ID
  • -keyalg   'RSA',  'DSA' , 'DES' 같은 키를 만들기위한 알고리즘 . 
  • -keystore  키스토어가 저장될 위치 

실행하면 다음과 같은것들을 물을것이다. 적절히 써넣자. (대한민국 국가코드는 KR) 


Roger$ keytool -genkey -alias MyKeyAlias -keyalg RSA -keystore /Users/Roger/tmp/roger.keystore
Enter keystore password: 
Re-enter new password:
What is your first and last name?
  [Unknown]:  localhost
What is the name of your organizational unit?
  [Unknown]:  MyDepartmentName
What is the name of your organization?
  [Unknown]:  MyCompanyName
What is the name of your City or Locality?
  [Unknown]:  Stafford
What is the name of your State or Province?
  [Unknown]:  NA
What is the two-letter country code for this unit?
  [Unknown]:  UK
Is CN=localhost, OU=MyDepartmentName, O=MyCompanyName, L=Stafford, ST=UK, C=UK correct?
  [no]:  Y

Enter key password for 
     (RETURN if same as keystore password): 

2. Tomcat 설정 변경 

톰캣이 SSL connector 를 가져야하는데 /conf 디렉토리에 보통 위치한 server.xml 파일에 아래를 추가한다.

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />

…and making it look something like this:

<Connector SSLEnabled="true" keystoreFile="/Users/Roger/tmp/roger.keystore" keystorePass="password" port="8443" scheme="https" secure="true" sslProtocol="TLS"/> 

위에서 password에 평문을 넣는것은 보안에 좋지 않다. 여러 방법이 있는데 이 포스트를 넘어서는것이다.

3. security-context.xml  설정 

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.1.xsd">
   
       <http auto-config='true' >
          <intercept-url pattern="/**" requires-channel="https" />    
       </http>
 
       <authentication-manager>
       </authentication-manager>

</beans:beans>

requires-channel="https" 를 추가하고 톰캣을 이용해서 시작하면  HTTPS 을 사용해서 접근할수있다. 

https://localhost:8443/my-app 요렇게 입력하면 작동할것이다. 
http://localhost:8080/my-app  요렇게 입력하면 자동으로 https 로 바뀔것이다.


+ Recent posts