Framework/Another Lore2009. 4. 23. 11:17

A Property object represents the smallest granularity of content storage.  A property must have one and only one parent node. A property does not have children. When we say that node A "has" property B it means that B is a child of A. A property consists of a name and a value.

All data stored within a AL repository is ultimately stored as the values of properties.


Property Types

STRING properties store instances of java.lang.String.

BOOLEAN properties store instances of the Java primitive type boolean.

LONG properties store instances of the Java primitive type long.

DOUBLE properties store instances of the Java primitive type double.

BINARY properties store instances of File

DATE properties store instances of java.util.Calendar.

NAME properties store instances of AlphaNumUnderBar

PATH properties store instances of AL paths and serve as pointers to locations within the workspace.PATH properties do not enforce referential integrity.

REFERENCE properties serve as pointers to referenceable nodes by storing their identifiers. REFERENCE properties do not enforce referential integrity

TEXT properties store instances of long length java.lang.String.

VIRTUAL_TEXT properties store template of string type


Property Type Conversion

When the value of a property is read or written using a type different from that declared for the property, the repository attempts a type conversion according to the following rules. Note that even in cases where the JCR type conversion is
defined in terms of standard JDK type conversion method, failure of conversion must only ever cause a JCR ValueFormatException to be thrown and never any exception defined in the JDK API.


Value Length

The length of a value is defined as follows:
For a BINARY value, its length is equal to its length in bytes. This number is returned both by Binary.getSize and by
Property.getLength and Property.getLengths

For other types, the length is the same value that would be returned by calling java.lang.String.getByte("UTF-8"). This number is returned by Property.getLength


[Example Code]
  IDString _string = IDString.propId("string");
  IDString _binary = IDString.propId("binary");
  IDString _long = IDString.propId("long");
  IDString _double = IDString.propId("double");
  IDString _date = IDString.propId("date");
  IDString _boolean = IDString.propId("boolean");
  IDString _name = IDString.propId("name");
  IDString _path = IDString.propId("path");
  IDString _reference = IDString.propId("reference");
  IDString _text = IDString.propId("text");
  IDString _integer = IDString.propId("integer");
  IDString _ftext = IDString.propId("ftext");
  PropertyDefinition[] pds = new PropertyDefinition[]{
    createProperty(_string, Property.Type.STRING), 
    createProperty(_binary, Property.Type.BINARY), 
    createProperty(_long, Property.Type.LONG), 
    createProperty(_double, Property.Type.DOUBLE), 
    createProperty(_date, Property.Type.DATE), 
    createProperty(_boolean, Property.Type.BOOLEAN), 
    createProperty(_name, Property.Type.NAME), 
    createProperty(_path, Property.Type.PATH), 
    createProperty(_reference, Property.Type.REFERENCE), 
    createProperty(_text, Property.Type.TEXT), 
    createProperty(_integer, Property.Type.INTEGER), 
    createProperty(_ftext, Property.Type.VIRTUAL_TEXT)
  } ;
  
  NodeType allType = createNodeType(objectType, "allType", pds) ;

  Node node = createNode(root, allType, "allType") ;
  node.setProperty(_string, (Object)"123") ;
  node.setProperty(_binary, (Object)TestValue.binaryValue) ;
  node.setProperty(_long, (Object)12311212121212L) ;
  node.setProperty(_double, (Object)123.3) ;
  Calendar cal = Calendar.getInstance();
  cal.setTime(DateUtil.string2Date("20060504-141224")) ;
  node.setProperty(_date, (Object)cal) ;
  node.setProperty(_boolean, (Object)true) ;
  node.setProperty(_name, (Object)"namedd") ;
  node.setProperty(_path, (Object)"path...") ;
  node.setProperty(_reference, (Object)root.getIdentifier()) ;
  node.setProperty(_text, (Object)new StringBuffer("abcdd")) ;
  node.setProperty(_integer, (Object)123) ;
  node.setProperty(_ftext, (Object)"$node.getUUIDString()") ;
  session.save() ;
  
  
  GenericIterator<Property> properties = node.getProperties() ;
  while(properties.hasNext()){
   Property property = properties.next() ;
   assertEquals(allType.getMappedDefinition(property.getId()).requiredType(), property.getValue().getPropertyType()) ;
  }
  
  assertEquals("123", node.getProperty(_string).getString()) ;
  assertEquals("111.jpg", node.getProperty(_binary).getString()) ;
  assertEquals("12311212121212", node.getProperty(_long).getString()) ;
  assertEquals("123.3", node.getProperty(_double).getString()) ;
  assertEquals("20060504-141224", node.getProperty(_date).getString()) ;
  assertEquals("true", node.getProperty(_boolean).getString()) ;
  assertEquals("namedd", node.getProperty(_name).getString()) ;
  assertEquals("path...", node.getProperty(_path).getString()) ;
  assertEquals(root.getIdentifier(), node.getProperty(_reference).getString()) ;
  assertEquals("abcdd", node.getProperty(_text).getString()) ;
  assertEquals("123", node.getProperty(_integer).getString()) ;
  assertEquals("$node.getUUIDString()", node.getProperty(_ftext).getString()) ;
  

  assertEquals("123", node.getProperty(_string).getObject()) ;
  assertEquals("jpg", ((BinaryPropertyValue)node.getProperty(_binary).getObject()).getContentType() ) ;
  assertEquals(12311212121212L, node.getProperty(_long).getObject()) ;
  assertEquals(123.3D, node.getProperty(_double).getObject()) ;
  assertEquals("20060504-141224", DateUtil.date2String((Calendar)node.getProperty(_date).getObject()) ) ;
  assertEquals(Boolean.TRUE, node.getProperty(_boolean).getObject()) ;
  assertEquals("namedd", node.getProperty(_name).getObject()) ;
  assertEquals("path...", node.getProperty(_path).getObject()) ;
  assertEquals(root.getIdentifier(), node.getProperty(_reference).getObject()) ;
  assertEquals("abcdd", node.getProperty(_text).getObject()) ;
  assertEquals(123, node.getProperty(_integer).getObject()) ;
  assertEquals(node.getIdentifier(), node.getProperty(_ftext).getObject()) ;
  
  node.setProperty(_boolean, "TRUE") ;
  assertEquals(true, node.getProperty(_boolean).getValue().getBoolean()) ;

  node.setProperty(_boolean, "true") ;
  assertEquals(true, node.getProperty(_boolean).getValue().getBoolean()) ;

  node.setProperty(_boolean, "1213") ;
  assertEquals(false, node.getProperty(_boolean).getValue().getBoolean()) ;

  try {
   node.setProperty(_long, "123a") ;
   fail() ;
  } catch(NotMatchePropertyTypeException ignore){
  }


< interface Property extends Cloneable, Serializable, IConstant, Publishable >
 public IDString getId();
 public Property newClone() throws RepositoryException;
 public Value getValue();
 public Property.Type getType() ;
 public String getTypeName();
 public String getString();
 public Node getNode() ;
 public void setValue(Value value);
 public boolean equalValue(Property property);
 public Object getObject() throws RepositoryException ;
 public Object getObject(Map param) throws RepositoryException;
 public void setMode(Mode mode) ;
 public Mode getMode() ;





3단계를 거치는 검사 정보를 저장하는 테이블을 설계한다고 하면 많은 프로그래머는

Create Table (processId varchar2(20), phase1 char(1), phase2 char(1), phase3 char(1)) 와 같이 만든다.


Process가 3단계라는건 어디까지나 현재시점이므로

Create Table(processId varchar2(20), phaseNo byte, phase char(1)) 로 하는게 좀더 유연하다.

processId당 1row를 읽었던 것을 3row로 읽기 때문에 성능이 떨어질 것이라고 생각하지만 IO는 byte의 양이며 양은 선이 아니라 넓이이다. 1 * 6 이나 3*2나 6*1이나 모두 양은 같으며 IO가 bit레벨이 아닌 kb의 일정한 단위로 이루어진다는 걸 생각하면 거의 영향이 없다. 오히려 동시성을 고려한 Lock 메커니즘을 생각하면 후자가 빠를때가 많다는 것은 DB에서는 상식에 가깝다. Table의 컬럼은 일종의 틀이며 제약이기 때문에 변할 가능성의 여부는 횡이 아니라 종에서 가능하도록 하면 설계의 유연성이 늘어난다. 대신에 1,2,3단계를 모두 통과한 process를 구하는 Query가 아주 조금 더 복잡해질 뿐이다.

이를 좀 더 극단적으로 생각하면 어떨까?
CREATE TABLE EMP
(
 EMPNO            NUMBER NOT NULL,
 ENAME            VARCHAR2 (10),
 JOB              VARCHAR2 (9),
 MGR              NUMBER (4),
 HIREDATE         DATE,
 SAL              NUMBER (7,2),
 COMM             NUMBER (7,2),
 DEPTNO           NUMBER NOT NULL
)
이라는 테이블은 극단적으로

Create Table property_tblc(
  propertyId varchar2(20) NOT NULL,
  propertyType varchar2(10) NOT NULL,
  propertyValue varchar(200)
)
로 바꿀수도 있다.

1102, bleujin, Dev, MGR, 2000.1.1, 100, 0, 20   이라는 row를

empNo, Number, 1102
ename, String, bleujin
job, String, Dev
mgr, String, MGR
....
와 같이 저장할수도 있다. 후자는 emp뿐 아니라 dept 테이블이라고 해도 모델이 변경될 필요가 없을정도로 극단적이다. 사실 이런 모델링은 이펙티브 오라클의 톰의 말대로 바보같은 모델링이다. 유연할지 모르겠지만 그 반작용은 아주 크다. 라고 죽 생각해 왔다.

그러나 경험상 30초짜리 쿼리를 3초로 줄이다든가 3초짜리 쿼리를 0.3초로 줄이면 클라이언트들은 아주 만족해 한다. 하지만 30ms 쿼리를 3ms 로 줄인다고 해서 기뻐하는 경우는 거의 없다.

다소 아이러니 하지만 ROI에서 본다면 당연한 이야기이다. 하나의 request에는 연산과 NetworkIO 등의 최소 한계 속도가 있다. CPU나 메모리의 연산속도는 ns지만 일반적으로 다루는 모든 I/O는 ms 단위로 이루어지게 된다. 30ms에서 3ms는 배수로는 동일하게 10배차이지만 하나의 request의 한계 속도가 0.3s라고 했을때 하나의 request는 고작해야 10%(27ms)도 안되는 차이가 있을뿐이다. 그리고 10%의 효과를 얻기 위한 비용은 막대하다.

초단위의 튜닝은 상대적으로 난이도가 쉽지만 ms단위의 튜닝은 수만줄의 DB쿼리에 각각에 대해 비싼 비용의 전문가들이 작성해야 하고 이미 그전에 하드웨어 튜닝, OS 튜닝, 그리고 물리적인 설계에서부터 테이블과 인덱스 옵션 하나하나의 제어와 통제, 다중사용자 환경을 고려한 Process와 Latch 경합에 대한 고려도 필요하다. 그럴바에는 차라리 초급 프로그래머가 대충 만들수 있는 이미지 등의 리소스 캐쉬가 비용도 작고 효과도 더욱 좋다. 

CPU 설계같은 일이 아닌 일반 어플리케이션에서 한자리수 ms 단위의 억세스는 ROI상 그렇게 효과적이지 못하다면 극단적으로 통제를 해서 얻는 27ms를 별로 관심도 없는 속도 향상에 투자하는게 아니라 아니라 여기서 얻는 여유를 몽땅 다른곳으로 돌려버리면 어떨까? 라는 시덥잖은 생각에서 출발했다.

'Framework > Another Lore' 카테고리의 다른 글

AL : Workspace  (0) 2009.04.23
AL : Node  (0) 2009.04.23
AL : PropertyDefinition  (0) 2009.04.23
AL : NodeType  (0) 2009.04.23
AL : Lock  (0) 2009.04.23
Posted by bleujin
Framework/Another Lore2009. 4. 23. 11:08

Property Definitions(속성정의) :
A node type contains a set of definitions specifying the properties that nodes of this node type are allowed (or required) to have and the characteristics of those properties.  A property definition has all the attributes of a generic item definition as well as the following property-specific attributes:


PropertyType

A property definition must specify a property type. Type[String, Binary, Long, Double, Boolean, Date, Name, Text, Reference, Path, ViertualText, Undefined] : defines integer constants for the available property types as well as for their standardized type names (used in serialization) and two methods for converting back and forth between name and integer value:

[Example Code]
 GlobalStore globalStore = session.getGlobalStore() ;
 PropertyDefinition explain = globalStore.createPropertyDefinition(IDString.propId("explain"), Property.Type.STRING) ;
 assertEquals(explain.requiredType(), Property.Type.STRING) ;

 NodeType newType = globalStore.createNodeType(objectType, "temporaryType", new PropertyDefinition[]{explain}) ;
  MappedDefinition md = newType.getMappedDefinition(IDString.propId("explain")) ;
  assertEquals(md.requiredType(), Property.Type.STRING) ;
  assertEquals(1, newType.getMappedDefinitions().size()) ;
  assertEquals("explain", md.getId().getString()) ;




<Inteface PropertyDefinition extends Serializable>
public IDString getId();
public boolean isSameProperty(IDString propId);
public Property.Type requiredType();



PropertyDefinition은 Id와 PropertyType으로 구성되어 있다.


DB의 컬럼과 비슷하기는 하지만 컬럼과 달리 constraint와 defaultValue를 가지지 않는다. 이러한 것들은 NodeType과 Mapping되는 과정에서 추가되고 PropertyDefinition은 단지 해당 아이디를 가진 PropertyDefinition은 특정 Property.Type을 가진다고 정의할 뿐이다.


'Framework > Another Lore' 카테고리의 다른 글

AL : Node  (0) 2009.04.23
AL : Property  (0) 2009.04.23
AL : NodeType  (0) 2009.04.23
AL : Lock  (0) 2009.04.23
AL : sequence  (0) 2009.04.23
Posted by bleujin
Framework/Another Lore2009. 4. 23. 04:46


An important feature of many repositories is the ability to distinguish the entities stored in the repository by type.
Node types are used to enforce structural restrictions on the nodes and properties in a workspace by defining for each node, its required and permitted child nodes and properties.

Every node has one declared node type. node types are typically used to defined the core characteristics of
a node. In a writable repository a node's primary type is first assigned upon node creation.

Repository implementations may vary as to how flexible they are in allowing changes to the node types assigned to a node. Each repository has a single, system-wide registry of node types. Typically, a repository will come with some implementation-determined set of built-in node types.

Some of these types may be vendor-specific while others may be standard predefined node types defined. Some repositories may further allow users to register new node types programmatically


A node type definition consists of the following attributes:


NodeTypeId


Every registered node type has a name, unique within the repository. NodeTypeId consists of prefix of AnotherLore URI and short local name in a workspace




Supertypes


A node type has zero or one supertype. Supertypes are specified by name. The supertype relation is transitive: If T1 is a supertype of T2 and T2 is a supertype of T3 then T1 is a supertype of T3.



Property Definitions

A node type may contain a list of property definitions, which specify the properties that nodes of that type are permitted or required to have and the characteristics of those properties. The list of property definitions may be empty.


Orderable Member NodeType

A node type may declare its member type orderable, meaning that for all nodes of that type, the order that the member nodes are iterated over can be programmatically controlled by the user. A node type may contain a list of member node definitions, which specify the permitted or required child nodes and their characteristics. member type definitions may be empty. if not setted, in principle have objectType(objectType have no propertyDefinition and is supertype of all nodetype)


Mapping Property Definition

The default values attribute of a property definition defines the values assigned to property if it is auto-created. If the property is single-valued this attribute will hold a single value.

A property definition may impose constraints on the value that the property may hold. These value constraints are defined by an array of strings, whose format differs depending on the type of the property.


[example Code]

NodeType commentType = globalStore.createNodeType(objectType, "comment", new PropertyDefinition[] { comment, regUserId, regDate });
  commentType.setConstraint(COMMENT, new RangeByteLengthConstraint(10, 4000));
  commentType.setConstraint(REGUSERID, new RequireConstraint());
  commentType.setConstraint(REGDATE, new RequireConstraint());      // set constraint
  commentType.setDefaultValue(REGDATE, new CurrentDateValue()) ;  // set default



<Inteface NodeType extends Serializable, Publishable>

 public NodeType setConstraint(IDString propId, IValueConstraint constraint)  throws RepositoryException ;
 public NodeType setDefaultValue(IDString propId, IDefaultValue defaultValue)  throws RepositoryException ;
 public NodeTypeId getId() ;
 public NodeType getSuperType()  throws RepositoryException ;
 public void setMemberType(NodeType memberType)  throws RepositoryException ; 
 public NodeType getMemberType()  throws RepositoryException ;
 public boolean isAllowedMemberType(NodeType memberType)  throws RepositoryException ;
 public GenericIterator<MappedDefinition> getMappedDefinitions() throws RepositoryException;
 public MappedDefinition getMappedDefinition(IDString propId) throws RepositoryException ;
 public boolean containsPropId(IDString propId)  throws RepositoryException ;
 public boolean isNodeType(NodeType thatType)  throws RepositoryException ;
 public boolean isNodeType(String thatTypeId)  throws RepositoryException ;
 public GenericIterator<ValidMessage> getViolateConstraintMessage(Node node) throws RepositoryException;




'Framework > Another Lore' 카테고리의 다른 글

AL : Property  (0) 2009.04.23
AL : PropertyDefinition  (0) 2009.04.23
AL : Lock  (0) 2009.04.23
AL : sequence  (0) 2009.04.23
자동화 테스트 - 자바스크립트  (0) 2009.04.17
Posted by bleujin