<script src="header.js"></script>

<div id="title"> Noradle topics </div>

servlet flow control
=====================

before & after filter
-----------------------------------

In Noradle, you can execute code before/after the main servlet procedure (target url-mapped-to procedure).
Before execute the target servlet procedure, Noradle will find and execute `k_filter.before` in the same schema.
You can code security check, preparation there, you can call the following API to do the right control.

* `h.go`
* `g.finish`
* `g.cancel`
* `g.filter_pass`

After executed the servlet procedure, Noradle will execute `k_filter.after`.
You can do log, gather run statics, or anything you need there.

Note: If no `k_filter` package exists in the servlet' schema, Noradle simply do nothing before and after the servlet
procedure execute, no exception will be raised.

instant jump out
----------------------------------------------------------------

Instant jump out of servlet processing is needed When the top procedlure call sub procedures,
for example, call common used checking sub procedures to do validation works.
When first check failure occurs, sub procedure can just report error and exit further page processing, it do not need to return to the top procedure and top procedure do not need to judge if check is not passed, and goto the label at end of line of the top procedure.You code g.finished or g.cancel to instantly  and exit page processing pass control to Noradle's servlet
 container. You do instant jump out bt calling `g.finish, g.cancel`.

```
package ...

  procedure main is
  begin
    check1;
    check2;
    proc1;
    proc2;
  end;

  procedure check1 is
  begin
    if r.getn('amount',0) > 100 then
      -- print error info
      g.cancel; -- main.check2 will never execute, main don't need to check check1's return value
    end if;
    -- if no error is checked out, main.check2 will execute by sequence.
  end;

  procedure proc1 is
  begin
    -- do processing
    if proc1 is enough to service client then
      g.finish; -- main.proc2 will never execute, since supporting procedure "proc1" alone will be ok.
    end if;
    -- but if "proc1" is not enough, main.proc2 will continue to execute.
  end;

end ...;
```

* `g.finish` : commit transaction and jump out of current servlet processing
* `g.cancel` : rollback transaction and jump out of current servlet processing
* `g.filter_pass` : jump out of k_filter.before and execute target(url mapped to) procedure

flush intermediate content
----------------------------

You can call `h.flush` to flush buffered http entity content to nodejs and maybe then to browser.

The first call to `h.flush` will make response headers send, followed by the content in buffer,
the header values if not set will be default
value, so "transfer-encoding" will be "chunked".

When a page is made up of stages, each stage may take time to generate, at that case,
call `h.flush` when a stage is finish will let nodejs and browser to get content pieces more quickly.

Another case, you can call `h.flush` in a sql fetch loop at given returned rows, so the user don't wait all rows is
fetched and processed to see just first of rows. like this:

```
for i in (select rownum rn, a.* from table a where ...) loop
  p.xxx(); ...
  if mod(i.rn,10)=0 then
    h.flush;
  end if;
end loop;
h.flush();
```

post redirect to feedback
--------------------------

after "_c" unit processed posted data, redirect to feedback page whose content is generated from "_c" unit itself

g.feedback
g.feedback(true)
require page to generate a 30x redirect response, content will in the following page.
usually used in B/H layer, so some exception info can be temporarily show in other url.

g.feedback(false)
for C layer, default behavior will send content in a redirected feedback page,
but with g.feedback(false)，content will be in the C layer url's response directly.
usually when C layer do some check work in AJAX request, responde directly.


linked/embed component CSS
---------------------------

HTML page may consist of many parts, each part may be generated by a encapsulated procedure.
So, Each page component is made by its counterpart procedure.
Each page have its own css, if a top page include a component, the component procedure will print its own css.
The key idea is css that's belong to a particular component will generated in its component,
and all components' css will be placed in top page html>head>style section altogether or be placed in subsequent css
request linked from the top page.

* p.comp_css_link(true)  will let all component css text write to a separate css file linked by top page
* p.comp_css_link(false); will let all component css test write to head in the top page
* p.comp_css_link(null); will disable css component feature for the current request

```
procedure component_css is
    procedure component is
    begin
      p.div_open(id => 'id1');
      p.lcss('p{line-height:1.5em;margin:0px 2em;color:gray;}');
      p.p('This is div component with some p in it, This div component can control it''s css within itself,' ||
          'no matter which page include the div, the css assosiated with the div is there.');
      p.div_close;
    end;
  begin
    p.comp_css_link(true);
    p.h('', 'component css');
    component;
  end;
```

will procedure
```
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
...
<link type="text/css" rel="stylesheet" href="css/EA684A9EEB587B07EF746D41882DE073"/></head>
<body>
<div id="id1">
  <p>This is div component with some p in it, This div component can control it's css within itself,no matter which page include the div, the css assosiated with the div is there.</p>
</div>
</body>
</html>
```

and css file whose relative url is "css/EA684A9EEB587B07EF746D41882DE073",

```
div#id1 p{line-height:1.5em;margin:0px 2em;color:gray;}

```

Note that css url after "css/" is the MD5 digest value of the generated css entity.
And Noradle automatically add a <link> whose href is linked to the generated css entity.
If p.comp_css_link(false) is called, then css text will be embed in top page, like this:

```
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
...
<style>
 div#id1 p{line-height:1.5em;margin:0px 2em;color:gray;}
</style></head>
<body>
<div id="id1">
  <p>This is div component with some p in it, This div component can control it's css within itself,no matter which page include the div, the css assosiated with the div is there.</p>
</div>
</body>
</html>

```

http protocol related
=====================


chunked transfer and buffer flush
----------------------------------

Whether buffer flush is allow if related with "Transfer-Encoding", "Content-MD5", "ETag", "feedback","component css".

GZIP
----------------------------

content-encoding can use gzip compress.
h.content-encoding-gzip will force noradle to return gzipped response.
h.content-encoding-identity force noradle to return original response.
h.content-encoding-auto(default) will see
1. if use content-length header, if length is more than threshold, use gzip
2. if use content-transfer=chunked, if first flush to nodejs is more than threshold, use gzip
Note, if all or first flush output's length is too low, gzip will probably get larger response, so Noradle will avoid gzip in that case.


automatical etag validation 304
--------------------------------

`h.etag_md5_on` will turn on automatic digest comparison to avoid send response entity when the client or intermediate
server have the same entity in its cache. Noradle will compute the digest value of the final produced entity/page,
then set http response header "ETag" to the digest value. When the client request the same servlet,
Noradle will check request header "If-None-Match", if its value is equal to the just generated digest value,
Noradle will response with http 304 response with empty http entity, so the client can just use its cache (validated
fresh), network transfer of response entity is avoided. `h.etag_md5_off` will turn the feature off. If the page
set http status code other than 200, "auto-etag-304" feature will turn off.


last_modified and 304
-----------------------

If all the ingredients of the servlet response is not modified, the response is not modified.
So, check each ingredient's last_modified and update the staged response last_modified by calling `h.last_modified
(date)`, if the final "last_modified" highest value is equal to http request header "if-modified-since",
then you can judge the response will not be a new one, so response with 304 status code and empty entity.
That way, you avoid actually generate the response entity and all the network transfer and processing of it.

`h.last_modified(date)` will record the high-water-mark value of all call's inut parameter value.
So, when get each part's "last_modified", use it to call `h.last_modified`.
After this, call `h.check_if_not_modified_since` to compare with request's "if-modified-since",
if it's really equal or not modified, the API call will response status 304 and jump out servlet execution.

```
procedure last_modified is
begin
	h.expires_now;
	h.last_modified(trunc(sysdate));
	select max(a.last_ddl_time) into tmp.dt from user_objects a;
	h.last_modified(tmp.dt);
	h.check_if_not_modified_since;

	p.h;
	src_b.link_proc;
	p.p('When this page is accessed, It may return 304 not modified for the entire day until mid-night.');
	p.p('But if you modified/compiled some of the schema objeccts, It will detect the change and return the current version');
	p.p('The last-modified-time will be max of the 00:00 in the morning or last-ddl-time of the schema objects.');
	p.p('You can call h.last_modified multiple times, then call h.header_close, ' || '
	the last-modified header will be set the lasted date value of them, ' ||
			'So if the page have many parts, you can call h.last_modified for each part''s last modified time.');
	p.br;

	for i in (select * from user_objects a where a.object_type != 'PACKAGE' order by a.last_ddl_time desc) loop
		p.p(t.dt2s(i.last_ddl_time) || ' > ' || i.object_name);
	end loop;
end;
```

manual etag
-----------------

Like `h.last_modified` and `h.check_if_not_modified_since` API usage and automatic digest ETag,
you can set your own ETag manually by calling `h.etag(value)`, if http request header "If-None-Match" is same as the
new etag "value", then response will be the same as the client's cached entity. So,
Noradle will jump out of servlet execution and response with 304 status code and empty entity.

mime-type
----------------------------

By default, Noradle servlet will produce "text/html" http response, that's to say,
Noradle will set http response header "Content-Type" to "text/html",
but response entity are simply text entity, you can set "Content-Type" to any mime-type,
If you print table data as a html table, you can set "Content-Type" to "application/vnd.ms-excel",
So browser will treat the response as excel file download.
So you can just produce "text/plain", "text/xml", "text/...".

Call `h.content_type` to set http response entity mime-type

```
procedure content_type
(
	mime_type varchar2 := 'text/html',
	charset   varchar2 := 'UTF-8'
)
```

file download
----------------------------

Call `h.content_disposition_attachment('filename.ext');` to let browser treat response entity as file download.

For example, download a excel sheet whose data is from database table.

```
procedure excel is
  cursor c_packages is
    select * from user_objects a where a.object_type = 'PACKAGE' order by a.object_name asc;
begin
  h.content_disposition_attachment('test.xls');
  p.doc_type('5');
  p.h;

  p.table_open(rules => 'all', cellspacing => 0, cellpadding => 5, ac => st('#border:1px solid silver;'));
  p.caption('table example');
  p.thead_open;
  p.tr(p.ths(st('package name', 'created')));
  p.thead_close;
  p.tbody_open;
  for i in c_packages loop
    p.tr_open;
    p.td(i.object_name);
    p.td(t.d2s(i.created));
    p.tr_close;
  end loop;
  p.tbody_close;
  p.table_close;
end;
```

file upload
----------------------------


### oracle can specify where the upload file will be saved

1) full path including directory and filename with ext.
```
	<input type="hidden" name="_file" value="test/filename.ext"/>
	<input type="file" name="file" />
	If upload file name is "myfile.jpg"
	The file will save at test/filename.ext
```

2) only directory where the original named file will be saved
```
	<input type="hidden" name="_file" value="test/"/>
	<input type="file" name="file" />
	Note that the _file's value is "test/" where the last character is "/"
	If upload file name is "myfile.jpg"
	The file will save at test/myfile.jpg
```

3) full path including directory and filename with ext the same as original file's ext.
```
	<input type="hidden" name="_file" value="test/filename."/>
	<input type="file" name="file" />
	Note that the _file's value is "test/filename." where the last character is "."
	If upload file name is "myfile.jpg"
	The file will save at test/filename.jpg
```

### if not specify saving path, node will use random path

  Noradle will generate a 32-bytes hex string for the saving filename,
By default, Noradle will split the hex string to two 16-bytes hex string and join them using "/",
This way, if too many file are uploaded, the upload file saving root directory will not be filled with too much file,
that will cause finding in the big directory very slow.

  You can specify in cfg.js to set upload_depth to 1,2,3,4 for deeper directory, that is

1. auto/32.ext
2. auto/16/16.ext
3. auto/10/10/12.ext
4. auto/8/8/8/8.ext

### anti script infection mechanism

  If upload file's content-type is "text/html" or the upload file's extension is .html or .htm, PSP.WEB will stripe all `<script>` tags, that will prevent the html file from loading or executing harmful javascript code, such as to stolen other user's identity cookie value.

Note: This feature is not implemented yet.

charset
=============================

h.content_type(mime_type,charset)

if http charset is db charset, Noradle use varchar2 for output buffer, so charset convertion is never occurred, no overhead.

if http charset is db national charset(UTF8,AL32UTF8,AL16UTF16...), Noradle will use nvarchar2 for output buffer, so if you put your varchar2 data to the response page,  oracle will take effort to do the implicit charset convertion. But buffer data will write directly out, no further convertion will occur.

if http charset is nether db charset or db national charset, Noradle will use nvarchar2 for output buffer, so every charset can be put into the buffer, converted or not converted. When flush the buffer, Noradle will convert the nvarchar2 buffer data to the specified charset. So some charset convertion work is due to occur.

http get/port parameter values will saved as its escaped format, what charset to parse it can be specified, default is equal to the the page specified output charset.

r.req_charset(cs varchar2)  take specified charset(in oracle name) as the parameter's charset
r.req_charset_db  take db charset as the parameter's charset
r.req_charset_ndb take db national charset as the parameter's charset
r.req_charset_utf8 take AL32UTF8 as the parameter's charset

procedure r.getc can give parameter value in ether varchar2 or nvarchar2 inout nocopy variables
function r.getc will return parameter as nvarchar2 value

h.use_bom will output bom(EFBBBF) following the http response headers
It can be used to provide none-html mime-type download utf-8 files like excel that can be viewed in excel on windows OS.
Warning: It is just conflict with gzip content-encoding at now.

internal
-----------

`pv.cs_char nls_charset_name(nls_charset_id('CHAR_CS'))`

`pv.cs_nchar := nls_charset_name(nls_charset_id('NCHAR_CS'))`

If response charset is `nls_charset_name(nls_charset_id('CHAR_CS'))`, Noradle will buffer page in varchar2 index-by
array, if response charset is `nls_charset_name(nls_charset_id('NCHAR_CS'))`, such as "AL32UTF8" or "AL16UTF16",
Noradle will buffer page in nvarchar2 index-by array. Ether case, Noradle will known the "content-length" by just sum
 the `lengthb` of the varchar2 or nvarchar2 array. But when response charset is not in nether 'CHAR_CS' nor
 'NCHAR_CS', Noradle will convert charset along with buffer output, so it's until all page is flushed to nodejs from
 oracle, it cannot tell the "content-length", but at the end of buffer flush, give "content-length" to node is
 useless because nodejs have already count the bytes, and it's better to use chunked transfer if it can.

 So noradle suggest AL32UTF8 for national charset for oracle database, cause most of http response will choose
 "UTF-8" http encoding, a AL32UTF8 database will never take burden to have charset conversion overhead.

`pv.pg_nchar boolean` indicate if use national charset buffer.

server cache
========================



<script src="footer.js"></script>