Customizing and Developing self-defined datasource

Once input self-defined datasource table in topic's basic info, system will automatically generate a table named as “the name of the self-defined datasource table"_prop, which we called “prop table”. This table can be used to manage the status of self-defined datasource. Its structure is showed as below:

CREATE TABLE "the name of the self-defined datasource table"_prop (ID VARCHAR2(50) NOT NULL,
     TITLE VARCHAR2(1000) NOT NULL,
     SITEID VARCHAR2(10) NOT NULL,
     TOPIC VARCHAR2(10) NOT NULL,
     STATE NUMBER,
     CREATEDATE DATE DEFAULT SYSDATE NOT NULL,
     PUBLISHDATE DATE,
     CONSTRAINT PK_"the name of the self-defined datasource table"_prop PRIMARY KEY (ID,TOPIC)
);
COMMENT ON COLUMN "the name of the self-defined datasource table"_prop.TITLE IS ''title';
COMMENT ON COLUMN "the name of the self-defined datasource table"_prop.SITEID IS 'site id';
COMMENT ON COLUMN "the name of the self-defined datasource table"_prop.TOPIC IS 'topic id';
COMMENT ON COLUMN "the name of the self-defined datasource table"_prop.STATE IS 'status';
COMMENT ON COLUMN "the name of the self-defined datasource table"_prop.CREATEDATE IS 'create date';
COMMENT ON COLUMN "the name of the self-defined datasource table"_prop.PUBLISHDATE IS 'publish date';

See also

top

Class CustomArticle

All categories of self-defined datasource must be derived from CustomArticle. CustomArticle can realize self-defined datasource under default situation. Below are its features:
1.Fields will be stored as TagRS format except “id”, “title”, “createdate” and “publishdate”. TagRS is similar to “Hashtable”, which take datasource’s capitalized field name as index.

2.Operations on attachment are unavailable. All operating values for attachment tag are null.

3.It provides default support for serial NpsEvent. All these events will solely respond to events launched by current topic.
    1)default response for InsertEvent: insert data into prop table which designated by topic. If Topic designates “publishing” as its default status, it should be published.
    2)default response for UpdateEvent: update the “title” value which is in “prop” table. If the status of current article is “published” or “to publish”, it should be re-published.
    3)default response for DeleteEvent: if the article is already published, all static pages, SOLR index and “prop” table record should be deleted.
    4)default response for Ready2PublishEvent: publish the article, and automatically generate “PublishEvent” notice.
    5)default response for PublishEvent: deliver to SOLR for fulltext index.

4.Not provide front-end management interface. If you need to manage self-defined datasource in NPS, you should re-develop it.

Constructor
public CustomArticle(NpsContext inCtxt,Topic top,ResultSet rs) throws Exception
Configure “CustomArticle” according to database’s result set. Note: the result set which is automatically loaded during the system publishing period can only include the field of “prop” table and of self-defined datasource major table.

Product example code:
public Product(NpsContext inCtxt,Topic top,ResultSet rs) throws Exception
{
     super(inCtxt,rs.getString("id"),rs.getString("title"),top);

     //load main information
     LoadMainInfo(rs,0);

     //load local information
     LoadLocalInfos();

     //load picture
     LoadAttaches();

     //load notified user
     LoadNotifyInfo();
}
override methods for IPublishable
public boolean HasFiled(String fieldName)
Judge whether the field has been named as “fieldName” or not. If yes, it will return “true”, otherwise, it will return “false”.

public Object GetField(String fieldName) throws NpsException
Obtain the field value which is named as “fieldName”. Return the specific “Object”. CLOB type will return “Reader” object.

Product example code:
public boolean HasFiled(String fieldName)
{
     if(fieldName==null || fieldName.length()==0) return false;
    
     String key = fieldName.trim();
     if(key.length()==0) return false;
    
     key = key.toUpperCase();
    
     if(key.equalsIgnoreCase("name")) return true;
     if(key.equalsIgnoreCase("code")) return true;//产品代码
     if(key.equalsIgnoreCase("category")) return true;
     if(key.equalsIgnoreCase("origin")) return true;
     if(key.equalsIgnoreCase("producer")) return true;
     if(key.equalsIgnoreCase("exporter")) return true;
     if(key.equalsIgnoreCase("brand")) return true;
     if(key.equalsIgnoreCase("material")) return true;
     if(key.equalsIgnoreCase("product_size")) return true;
     if(key.equalsIgnoreCase("product_weight")) return true;
     if(key.equalsIgnoreCase("carton")) return true;
     if(key.equalsIgnoreCase("carton_weight")) return true;
     if(key.equalsIgnoreCase("purchase_price")) return true;
     if(key.equalsIgnoreCase("price")) return true;
     if(key.equalsIgnoreCase("fob")) return true;
     if(key.equalsIgnoreCase("package_quantity")) return true;
     if(key.equalsIgnoreCase("lead_time")) return true;
     if(key.equalsIgnoreCase("moq")) return true;
     if(key.equalsIgnoreCase("MinimumMoney")) return true;
     if(key.equalsIgnoreCase("product_spec")) return true;
     if(key.equalsIgnoreCase("package_spec")) return true;
    
    
     if(fields==null) return false;
     return fields.HasField(key);
}

public Object GetField(String fieldName) throws NpsException
{
     if(fieldName==null || fieldName.length()==0) return null;
    
     String key = fieldName.trim();
     if(key.length()==0) return null;
    
     key = key.toUpperCase();
    
     if(key.equalsIgnoreCase("name")) return name;
     if(key.equalsIgnoreCase("code")) return code;
     if(key.equalsIgnoreCase("category")) return category;
     if(key.equalsIgnoreCase("origin")) return origin;
     if(key.equalsIgnoreCase("producer")) return producer;
     if(key.equalsIgnoreCase("exporter")) return exporter;
     if(key.equalsIgnoreCase("brand")) return brand;
     if(key.equalsIgnoreCase("material")) return material;
     if(key.equalsIgnoreCase("product_size")) return product_size;
     if(key.equalsIgnoreCase("product_weight")) return product_weight;
     if(key.equalsIgnoreCase("carton")) return carton;
     if(key.equalsIgnoreCase("carton_weight")) return carton_weight;
     if(key.equalsIgnoreCase("purchase_price")) return purchase_price;//进价
     if(key.equalsIgnoreCase("price")) return purchase_price;
     if(key.equalsIgnoreCase("fob")) return fob;
     if(key.equalsIgnoreCase("package_quantity")) return package_quantity;//包装数量
     if(key.equalsIgnoreCase("lead_time")) return lead_time;
     if(key.equalsIgnoreCase("moq")) return moq;
     if(key.equalsIgnoreCase("MinimumMoney")) return GetMinimumMoney();
     if(key.equalsIgnoreCase("product_spec")) return product_spec;
     if(key.equalsIgnoreCase("package_spec")) return package_spec;


     if(fields==null) return null;
     return fields.GetField(key);
}
Fire Event
Publish event notice through “Fire” serial methods of “EventIssue”. Note: the “key” value of “Fire” method should be taken according to the table name of self-defined datasource (in uppercase).
"Product" example code:
//publish the ready-to-publish information, prepare each topic
public void Publish() throws NpsException
{
     //Fire Event
     EventIssue.GetIssue().FireReady2PublishEvent(this,"FT_PRODUCT");
}
NpsEvent handler
If the default event handler can not meet specific requirement, you should overload the “NpsEvent” processing function.
public void Insert(Object observer, InsertEvent event)
The response function for “InsertEvent”

public void Update(Object observer, UpdateEvent event)
The response function for “UpdateEvent”

public void Delete(Object observer, DeleteEvent event)
The response function for “DeleteEvent”

public void Ready(Object observer, Ready2PublishEvent event)
The response function for “Ready2PublishEvent”

public void Publish(Object observer, PublishEvent event)
The response function for “PublishEvent”

"Product" example code:
//The topic is concerned on its own product
public void Insert(Object observer, InsertEvent event)
{
     if(observer instanceof Topic)
     {
         Topic t = (Topic)observer;
         if(!unit_id.equals(t.GetSite().GetUnit().GetId())) return;
         super.Insert(t,event);
     }
}
top

Class Attach

“Attach” class is the base class of all attachment class. “Article” class is responsible for managing “Attach” collection.

IPublishable implementation
public String GetURL()
Return the “URL” path of published “Attach”.

public File GetOutputFile()
Return the location of temporary files.

"Product" example code:
public String GetURL()
{
     return PRODUCT_ATTACH_URL
     + Utils.FormateDate( art.GetCreateDate() , "yyyy/MM/dd")
     + "/"
     + id
     + (suffix==null?"":suffix);
}
    
public File GetOutputFile()
{
     String temp_filepath = Utils.FormateDate(art.GetCreateDate(),"yyyy/MM/dd") +"/";
    
     temp_filepath = temp_filepath.replaceAll("//","/");
     if(temp_filepath.startsWith("/"))
     {
         temp_filepath = temp_filepath.substring(1);
     }
    
     File temp_file = new File( PRODUCT_ATTACH_PATH,temp_filepath);
    
     temp_file.mkdirs();
    
     return new File(temp_file, id + (suffix==null?"":suffix));
}
Cloneable implementation
public Object clone() throws CloneNotSupportedException
Provide the implementation of “clone” object. Below is the default implementation:
public Object clone() throws CloneNotSupportedException
{
     return super.clone();
}
top

custom.xml configuration

After developing Java class, you should configure “custom.xml” to realize automatic load.

Store location
“custom.xml” can be stored under the same directory of “nps.conf”, namely the “WEB-INF” directory.
Configuration guide
<?xml version="1.0" encoding="UTF-8"?>
<root>
    #Each kind of self-defined datasource should be independently put under one “CustomArticle” node. There could be multiple “CustomArticle” ports under “root” node.
     <CustomArticle>
         #Each “CustomArticle” node must have one “table” and “class” node, otherwise, it will be neglected when loading.
         #“table” means the table name of self-defined datasource that need to be applied. It should be capitalized.
         #“class” means the re-developed self-defined datasource name that need to be loaded. We advise to use fully qualified class name. The class must be put under “common/lib”、“WEB-INF/classes” and “WEB-INF/lib”.
         <table>FT_PRODUCT</table>
         <class>nps.extra.trade.Product</class>

         # “property” node is not necessary unless for self-defined configuration. “property” can be globally shared.
         # the name of “property” lower-level node is “property” variable name. Its value is variable’s dereference. Note: the value is the result of “trim”.
         <property>
             <PRODUCT_ATTACH_PATH>c:\\web\\products\\</PRODUCT_ATTACH_PATH>
             <PRODUCT_ATTACH_URL>/products/</PRODUCT_ATTACH_URL>
        </property>
     </CustomArticle>

         #“event” node is not necessary unless for processing self-defined event. With regard to the “NpsEvent” processing method which is overloaded by “CustomArticle” derived class, it is not necessary to configure it; the system will automatically load it when the system gets started.
         #There can only be four kinds of node (“insert”、“update”、“delete”、“ready” and “publish”) that under “event”. They should respectively match along with the “InsertEvent”、“UpdateEvent”、 “DeleteEvent”、“Ready2PublishEvent”、“PublishEvent”.
         #“key” value is the same as the “KEY” value which publish event notice in self-defined datasource.
         #The “Product” example below can be applied to automatically send customers e-mail when products get published.
     <event>
         <publish key="FT_PRODUCT">nps.extra.trade.ProductManager</publish>
     </event>
</root>