星期四, 十二月 25, 2008

文本聚类算法TCUSS(Text clustering using semantic similarity)

http://club.ufida.com.cn/blogs/rbg/archive/2008/05/28/_8259554F6E789A5B2D4E8765575B267B324E8476F8763C4FA65E2800_ZT_2900_.aspx

动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法

动态规划求解最长公共子串问题


算法思想

求字符串str1,str2的最长公共子串的长度。

定义二元函数函数f(m,n):分别以str1[m],str2[n]结尾的连续公共子串的长度

而对于f(m+1,n+1) 有以下两种情况

1.str1[m+1] != str2[n+1],则有f(m+1,n+1) =0

2.str1[m+1] == str2[n+1],则有f(m+1,n+1) = f(m,n) + 1

另外f(0,j) = 0(j>=0)

f(j,0) = 0 (j>=0)

按照上面这个公式,我们用容易写出这个算法的实现

算法实现

1 int commstr(char *str1, char *str2)

2 /* 返回str1,str2的最长公共之串长度*/

3 {

4 int len1=strlen(str1),len2=strlen(str2),row,col,max=0;

5 int **pf = new int*[len1+1];//动态分配一个二维数组作为辅助空间

6 for (row=0; row

7 pf[row] = new int[len2+1];

8

9 //数组赋初值

10 for (row=0; row

11 pf[row][0] = 0;

12 for (col=0; col

13 pf[0][col] = 0;

14

15 for (row=1; row<=len1; row++)

16 for (col=1;col<=len2; col++)

17 {

18 if (str1[row-1] == str2[col-1])

19 {

20 pf[row][col] = pf[row-1][col-1] + 1;

21 max = pf[row][col] > max ? pf[row][col] : max;

22 }

23 else

24 pf[row][col] = 0;

25 }

26 //空间回收

27 for (row=0; row

28 delete[] pf[row];

29 delete[] pf;

30

31 return max;

32 }



程序的输出

字符串"blog.csdn.net"和"csdn.blog"求公共子串时的输出结果

String:

1. blog.csdn.net

2. csdn.blog

c s d n . b l o g

0 0 0 0 0 0 0 0 0 0

b 0 0 0 0 0 0 1 0 0 0

l 0 0 0 0 0 0 0 2 0 0

o 0 0 0 0 0 0 0 0 3 0

g 0 0 0 0 0 0 0 0 0 4

. 0 0 0 0 0 1 0 0 0 0

c 0 1 0 0 0 0 0 0 0 0

s 0 0 2 0 0 0 0 0 0 0

d 0 0 0 3 0 0 0 0 0 0

n 0 0 0 0 4 0 0 0 0 0

. 0 0 0 0 0 5 0 0 0 0

n 0 0 0 0 1 0 0 0 0 0

e 0 0 0 0 0 0 0 0 0 0

t 0 0 0 0 0 0 0 0 0 0


max substr length:5

这是程序的输出结果,请注意红色字体


时间空间复杂度分析

如果用n,m表示两个字符串的长度的话,那么算法的

时间复杂度为O(n*m),空间复杂度也为O(n*m)

附:完整的源程序g++编译通过

#include

#include

void print_table(char *str1,char *str2,int **pf)

{

int i,j,row,col;

row = strlen(str1);

col = strlen(str2);

printf("\t\t");

for (i=0; i

printf("%c\t",str2[i]);

for (i=0; i<=row; i++)

{

for (j=0; j<=col; j++)

{

if (j == 0)

{

printf("\n");

if (i)

printf("%c\t",str1[i-1]);

else

printf("\t");

}

printf("%d\t",pf[i][j]);

}

}

}

int commstr(char *str1, char *str2)

/* 返回str1,str2的最长公共之串长度*/

{

int len1=strlen(str1),len2=strlen(str2),row,col,max=0;

int **pf = new int*[len1+1];//动态分配一个二维数组作为辅助空间

for (row=0; row

pf[row] = new int[len2+1];

//数组赋初值

for (row=0; row

pf[row][0] = 0;

for (col=0; col

pf[0][col] = 0;

for (row=1; row<=len1; row++)

for (col=1;col<=len2; col++)

{

if (str1[row-1] == str2[col-1])

{

pf[row][col] = pf[row-1][col-1] + 1;

max = pf[row][col] > max ? pf[row][col] : max;

}

else

pf[row][col] = 0;

}

print_table(str1,str2,pf);

//空间回收

for (row=0; row

delete[] pf[row];

delete[] pf;

return max;

}

int main(int argc,char **argv)

{

if (argc >= 3)

{

printf("String:\n\t1. %s\n\t2. %s\n",argv[1],argv[2]);

printf("\nmax substr length:%d\n",commstr(argv[1],argv[2]));

}

return 0;

}

星期三, 十二月 24, 2008

数据库自我关联

这个是SQLITE 得到一个记录和其随后记录的SQL:通过rowid来关联

select a.*,b.* from _dbhistory a left join _dbhistory b on a.rowid=(b.rowid-1)

星期五, 十一月 21, 2008

DhtmlxGrid 错误跟踪

function myErrorHandler(type, desc, erData)
{
//custom code can be placed here
return false;
}
dhtmlxError.catchError("LoadXML", myErrorHandler);

星期三, 十一月 19, 2008

SQLITE 3.6.5 SQL小窍门

1.得到最近的几期数据

where rowid>((select max(rowid) from 表名)-想要的记录条数)

星期一, 十一月 17, 2008

MathType快捷键

插入一个分数:Ctrl+F
插入一个上标:Ctrl+H
插入一个下标:Ctrl+L

Right arrow with upper text slot (Ctrl+T,Shift+Right) , 输入条件推理
Right arrow with lower text slot (Ctrl+T,CtrlAlt+Right) 输入条件推理
Right arrow with upper and lower text slots (Ctrl+T,Right) 输入条件推理
Curly brackets 大括号{
Left-pointing angle brackets 向左的尖括号<
Right-pointing angle bracket from Symbol style (Ctrl+Shift+K,>)
Left white square bracket from Extra Math style (Ctrl+Shift+K,[)
左白方括号
Right white square bracket from Extra Math style (Ctrl+Shift+K,])

星期四, 十一月 06, 2008

Java JPopupMenu selection 丢失。

Java JpopupMenu selection 有时候invisible,这种问题原因是事件丢失。
简单使用如下方法就可以了:

jpopup.setInvoker(jpopup);

如果想修改selection的颜色,可以使用如下方法,

UIManager.put("MenuItem.selectionBackground", Color.YELLOW);


星期三, 十一月 05, 2008

小窍门:Java如何让一个窗体显示在最上面?

SwingUtilities.windowForComponent( JPupupMenu ).window.setAlwaysOnTop( true )

使用这个方法可以做到。

如何在任何地方得到鼠标的的屏幕坐标?

jdk 6.0提供MouseInfo.getPointerInfo() .getLocation() 得到Point.getX(),.getY()

星期六, 十一月 01, 2008

如何选择JTable中任一行和任一列?

主要代码如下:

table.setModel(dayModel);
table.setCellSelectionEnabled(true);
table.getSelectionModel().setSelectionInterval(2, 2);
table.getColumnModel().getSelectionModel().setSelectionInterval(3, 3);
你可以修改上面的2行,3列为你自己的任一行或列。非常的easy

星期一, 十月 27, 2008

如何提高SQLITE JDBC大批量插入数据的速度?

应为每一个Insert into操作默认都需要一个事物,所以通过显示的声明一个事物,可以大大提高数据插入的时间。
类似语句如下:

stmt.execute("BEGIN");
for(int i=0;i<commands.length;i++)
{
stmt.addBatch(commands[i]);
}
stmt.executeBatch();
stmt.execute("end");

曾经大约800数据,使用默认方法插入,大概需要141秒,而采用新方法后,使用纯Java的JDBC
速度提高到4秒,而使用JNI的JDBC,速度提高到几乎可以忽略不计的地步。

Very nice.!!!

星期五, 十月 24, 2008

Java JScrollPane getVerticalScrollBar.setValue没有效果解决方法。

JScrollPane scroll=new JscrollPane(new JEditorPane());

toolTip.getContentPane().add(scroll);
toolTip.pack();

//以下代码可以让scroll滚动到top顶端。

SwingUtilities.invokeLater(new Runnable(){public void run()
{
scroll.getVerticalScrollBar().setValue(0);
}
});

星期四, 十月 23, 2008

Servlet download 如何为已知的 MIME 类型激活“文件下载”对话框?

根据微软的一个文章:http://support.microsoft.com/kb/q260519/
参考如下:
您可以使用 Content-disposition 头来覆盖此默认行为。其格式是:
Content-disposition: attachment; filename=fname.ext
ASP:代码

Response.AddHeader "content-disposition","attachment; filename=fname.ext"

Servlet代码:
realName="yourfiel.n";
response.addHeader("Content-disposition","attachment; filename="+realName);
//realName如果是汉字编码会造成出现不了制定的文件名的情况,需要编码
//把以上代码修改为
//response.addHeader("Content-disposition","attachment; filename="+java.net.URLEncoder.encode(realName,"UTF-8"));

response.setIntHeader("Content-length", (int)rs.getBlob("ATTACH_FILE").length());

InputStream is = rs.getBinaryStream("ATTACH_FILE");

byte[] buf = new byte[3000];
int read = 0;
while ((read = is.read(buf)) > 0)
{
// fos.write(buf, 0, read);
outs.write(buf, 0, read);
}
// fos.close();
is.close();
outs.flush();
// outs.close();
}


星期四, 十月 16, 2008

SQLite自定义函数简介

SQLite自定义函数简介

SQLite最大的特色之一就是可以用户定义函数。用户自定义函数可以像系统内置函数一样可以在注册之后像系统内置函数一样在SQL语句中使用。用户使用自定义函数类似存储过程,方便用户对常见功能的调用,也加快了执行速度。用户自定义函数整体上可以分为两种:简单函数和聚集函数。

简单函数(simple function)

简单函数用在任何表达式中,常见的有max(x,y..), min(x,y..), random(*), last_insert_rowid(), length(x),lower(x), upper(x), round(x,y), round(*), substr(x,y,z), typeof(x)

聚集函数(aggregate function)

聚集函数经常用在select语句中,常见的有avg(x),count(x), count(*), max(x), min(x), sum(x), total(x)

  有些函数既是简单函数,又是聚集函数。比如只有一个参数的min()是一个聚集函数,而有多个参数的min()是一个简单函数。

SQLITE比较好的书有两本:
一个是:O'Reilly出版的 Inside SQLite
一个是:Apress.The.Definitive.Guide.to.SQLite.May.2006

星期一, 十月 13, 2008

如何立即刷新Java Swing Jcomponent组件?

例子:按下一个button,调用JTextArea.setText()之后,JTextArea的内容不会立即更新,必须要等待button捆绑的ActionListener过程完全完成之后,才会刷新。
如果想立即刷新JTextArea的内容去,需要调用一下语句。

JTextArea sql2= new JTextArea(5,10);
Point pt=sql2.getLocation();
Dimension ds=sql2.getSize();
sql2.paintImmediately((int)pt.getX(),(int)pt.getY(), (int)ds.getWidth(),(int)ds.getHeight());

这个工作的非常好。

星期四, 十月 09, 2008

得到当前运行class的物理位置

可以使用如下简单语句:

URL classFileDir =new yourClassName().getClass().getResource(".");

print结果为:file:....的URL

星期三, 十月 08, 2008

Windows XP SP2手工修改屏幕分辨率

有时候设置了不对的屏幕分辨率,会造成屏幕发黑无法启动。这是有需要在启动的时候按下F6键,然后进入注册表删除设置的屏幕分辨率,
Intel(R) Extreme Graphics 除了在注册表:
HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control\VIDEO有引用,
本身在:
[HKEY_CURRENT_CONFIG\System\CurrentControlSet\SERVICES\IALM]也有设置,必须删除这个设置
再启动机器后,才能正常进入。

[HKEY_CURRENT_CONFIG\System\CurrentControlSet\SERVICES\IALM\DEVICE0]
[HKEY_CURRENT_CONFIG\System\CurrentControlSet\SERVICES\IALM\DEVICE0\Mon80861100]

这两个注册表项目要删除掉

星期六, 九月 27, 2008

beanshell Bsh.Console如何在jdk 1.6中使用

直接使用String.format(format,param)会出现错误。
必须使用如下语法,
String.format("%3.2f",new Object[]{(float)6/11});

就可以使用了

星期五, 九月 19, 2008

dhtmlXGrid 覆盖函数。

这是覆盖每个cell 动态的tooltip的提示的方法。

dhtmlXGridCellObject.prototype.getTitle=function()
{
ccolName=this.grid.getColumnId(this.cell._cellIndex);
rowID=this.cell.parentNode.idd;
result=this.cell.innerHTML;
if(ccolName=='RULE_NAME')
result=this.grid.cells(rowID,4).getValue();
return result;
}

修改每个行的颜色
mygrid.setRowColor(rowid,"yellow");
或者更加底层的,可以修改更多属性CSS

mygrid.rowsAr[idrow].style.backgroundColor="yellow"

星期四, 九月 18, 2008

dhtmlXGrid 1.3版本如何修改每个cell的帮助提示呢?Tooltip

经过dhtmlXGrid论坛发现了一个渐变的方法。

dhtmlXGridCellObject.prototype.getTitle=function()
{
return this.cell.innerHTML+"<h1>F1 HELP</H1><BR/><P>..."+this.cell._cellIndex+"|||"+this.grid.getColumnId(this.cell._cellIndex);
}

不过这个innerHTML只承认纯文本,所以HTML语法无法使用了,\nJavascript符号还是认识的。


星期六, 九月 13, 2008

JBOSS JAAS如何编写自己的身份(principal)?

详细的步骤在:http://wiki.jboss.org/wiki/UsingCustomPrincpalsWith
不过经过事件发现只需要重载两个方法就可以了。如果直接从org.jboss.security.auth.spi.DatabaseServerLoginModule扩展,这样可以利用JBOSS已经有的密码加密,编码等其他一些特性,不需要再重写。

类似如下:
public class StandardLoginModule extends DatabaseServerLoginModule
编写自己的定制身份类Principal,可以加入除了名字之外的其他属性.

public class userPropertiesPrincipal extends SimplePrincipal
{
//User's property
private String email;
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email=email;
}
//gender
private String gender;
public String getGender()
{
return gender;
}
public void setGender(String gender)
{
this.gender=gender;
}
public userPropertiesPrincipal(String name)
{
super(name);
}

}

必须重载的三个方法(红色)
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options)
   public boolean login() throws LoginException
{
}
   protected Principal getIdentity()
{
 可能需要重载的类.
protected Group[] getRoleSets() throws LoginException
{}

具体设置步骤:在login-config.xml里加入,通过
principalClass来制定自己定制的身份类.也注意加入了
userPropertiesQuery,这个需要在initialize方法中从Map options中取出来,如下:
super.initialize(subject, callbackHandler, sharedState, options);

userPropertiesQuery=(String ) options.get("userPropertiesQuery");
if(userPropertiesQuery==null)
userPropertiesQuery="select * from sysUser where userid=?";


<application-policy name = "seamAC">
<authentication>

<login-module code = "org.security.login.jass.StandardLoginModule"
flag = "required">

<module-option name = "dsJndiName">java:/SecMasterDS</module-option>
<module-option name = "principalsQuery">select password from sysUser where userid=? </module-option>
<module-option name = "userPropertiesQuery">select * from sysUser where userid=? </module-option>
<module-option name = "rolesQuery">SELECT A.roleID as Role,'Roles' FROM sysRoles A,UserRoles B WHERE A.roleID=B.roleID AND B.userId=?</module-option>
<module-option name = "debug">true</module-option>
<module-option name="principalClass">org.security.login.jass.userPropertiesPrincipal</module-option>
<!--Password is md5 encrypt-->
<module-option name="hashAlgorithm">MD5</module-option>
<module-option name ="hashEncoding">HEX</module-option>
</login-module>
</authentication>
</application-policy>

Web.xml中必须指明使用使用JAAS Security Manage RealM

<Realm className="org.jboss.web.tomcat.security.JBossSecurityMgrRealm"
certificatePrincipal="org.jboss.security.auth.certs.SubjectDNMapping"
allRolesMode="authOnly"
debug="99"
/>

星期四, 九月 11, 2008

Jboss如何获取用户验证后的角色?

通过JAAS验证的用户,要想得到验证的用户的所有的角色,JBOSS目前推荐的是如下代码段
主要是基于新的JACC规范:
Java Authorization Contract for Containers (Java ACC) specification (JSR-115)

import javax.security.auth.Subject ;
import javax.security.jacc.PolicyContext;

private String findRole() throws Exception
{
String result="";

// Get the Authenticated Subject
Subject subject = (Subject) PolicyContext.getContext("javax.security.auth.Subject.container");

// Now look for a Group called Roles
Set principals = subject.getPrincipals(Principal.class);
Iterator iter = principals.iterator();
while(iter.hasNext())
{
Principal p = (Principal)iter.next();
if(p instanceof SimpleGroup)
{
SimpleGroup sg = (SimpleGroup)p;
if("Roles".equals(sg.getName()))
{
Enumeration en = sg.members();
while(en.hasMoreElements())
{
String role = en.nextElement().toString();
result=result+","+role;
System.out.println("Role:"+role);
}
}
}
}
return result;
}

JAASRealm和Jboss(CMA) Container Manager Authentication

这是为了结合JAAS和CMA两者的有点提出的接口。
在http://www.jboss.org/file-access/default/members/jbossweb/freezone/docs/2.1.0/realm-howto.html#JAASRealm,描述了相关配置
web.xml

<Realm className="org.jboss.web.tomcat.security.JBossSecurityMgrRealm"
certificatePrincipal="org.jboss.security.auth.certs.SubjectDNMapping"
allRolesMode="authOnly"
debug="99"
/>


其他配置同JAAS标准配置一样,需要在web.xml,login-config.xml和LoginModule中调用同一个appName

但是注意,在这个LoginModule你必须自己保存用户的验证信息。
It is the responsibility of your login module to create and save User and Role objects representing Principals for the user

下列代码就是Jboss实现的:org.jboss.web.tomcat.security.login.WebAuthentication


/*
* JBoss, Home of Professional Open Source
* Copyright 2007, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.web.tomcat.security.login;

import java.security.Principal;
import java.security.cert.X509Certificate;

import javax.naming.NamingException;

import org.apache.catalina.Session;
import org.apache.catalina.authenticator.Constants;
import org.apache.catalina.connector.Request;
import org.jboss.web.tomcat.security.SecurityAssociationValve;

//$Id$

/**
* JBAS-4077: Programmatic Web Login
* @author Anil.Saldhana@redhat.com
* @since Mar 12, 2007
* @version $Revision$
*/
public class WebAuthentication
{
private static final String AUTH_TYPE = "PROGRAMMATIC_WEB_LOGIN";
public WebAuthentication()
{
}

/**
* Login an user via the CLIENT-CERT method
* @param certs X509 certificates
* @return Authenticated User Principal
*/
public boolean login(X509Certificate[] certs)
{
//Get the active request
Request request = (Request) SecurityAssociationValve.activeRequest.get();
if(request == null)
throw new IllegalStateException("request is null");
Principal p = request.getContext().getRealm().authenticate(certs);
if(p != null)
{
register(request,p, null, null);
}
return p!= null;
}

/**
* Login an user via the BASIC, FORM, DIGEST methods
* @param username
* @param credential
* @return
* @throws NamingException
*/
public boolean login(String username, Object credential)
{
//Get the active request
Request request = (Request) SecurityAssociationValve.activeRequest.get();
if(request == null)
throw new IllegalStateException("request is null");

Principal p = null;
if(credential instanceof String)
{
p = request.getContext().getRealm().authenticate(username, (String)credential);
}
else if (credential instanceof byte[])
{
p = request.getContext().getRealm().authenticate(username, (byte[])credential);
}
if(p != null)
{
register(request,p, username, credential);
}
return p != null;
}

/**
* Log the user out
*
*/
public void logout()
{
//Get the active request
Request request = (Request) SecurityAssociationValve.activeRequest.get();
if(request == null)
throw new IllegalStateException("request is null");
unregister(request);
}

/**
* Register the principal with the request, session etc just the way AuthenticatorBase does
* @param request Catalina Request
* @param principal User Principal generated via authentication
* @param username username passed by the user (null for client-cert)
* @param credential Password (null for client-cert and digest)
*/
protected void register(Request request, Principal principal, String username, Object password)
{
request.setAuthType(AUTH_TYPE);
request.setUserPrincipal(principal);

//Cache the authentication principal in the session
Session session = request.getSessionInternal(false);
if(session != null)
{
session.setAuthType(AUTH_TYPE);
session.setPrincipal(principal);
if (username != null)
session.setNote(Constants.SESS_USERNAME_NOTE, username);
else
session.removeNote(Constants.SESS_USERNAME_NOTE);
if (password != null)
session.setNote(Constants.SESS_PASSWORD_NOTE, getPasswordAsString(password));
else
session.removeNote(Constants.SESS_PASSWORD_NOTE);
}
}

/**
* Log the user out
* @param request
*/
protected void unregister(Request request)
{
request.setAuthType(null);
request.setUserPrincipal(null);

//Cache the authentication principal in the session
Session session = request.getSessionInternal(false);
if(session != null)
{
session.setAuthType(null);
session.setPrincipal(null);
session.removeNote(Constants.SESS_USERNAME_NOTE);
session.removeNote(Constants.SESS_PASSWORD_NOTE);
}
}

private String getPasswordAsString(Object cred)
{
String p = null;

if(cred instanceof String)
{
p = (String)cred;
}
else if(cred instanceof byte[])
{
p = new String((byte[])cred);
}
return p;
}
}

星期三, 九月 10, 2008

JBOSS JAAS和tomcat j_security_check CMS关系(之二)

Jboss 的 WebAuthentication的login方法到底做了什么工作?将JAAS和tomcat container链接了起来?
这个要查看代码:

http://www.javakey.net/source/jboss/4.x/org/jboss/web/tomcat/security/login/WebAuthentication.java.html

从这里可以看到,如何从tomcat中获取当前激活的
 org.apache.catalina.connector.Request(http://www.docjar.com/html/api/org/apache/catalina/connector/Request.java.html)
的后门方法

Request request = (Request) SecurityAssociationValve.activeRequest.get();

这个方式是非常cool的
.这里实际调用了Request上下文的RealM的
authenticate多元方法.
这个方法是在tomcat web.xml里通过来定义的。
比如:jboss 4.2.3GA. server\default\deploy\jboss-web.deployer\server.xml
里定义:
<realm classname="org.jboss.web.tomcat.security.JBossSecurityMgrRealm" certificateprincipal="org.jboss.security.auth.certs.SubjectDNMapping" allrolesmode="authOnly">

Jboss相关类源代码:http://www.javakey.net/source/jboss/4.x/allClasses.html
整个工作流程:
JAASRealm authenticates the user and creates a GenericPrincipal with
userPrincipal set to some principal returned by LoginModule.

Later RealmBase.hasResourcePermission() calls request.getUserPrincipal()
to recover authenticated user principal

Request.getUserPrincipal() checks if the principal is instanceof
GenericPrincipal, and if it is, it returns its userPrincipal.

RealmBase.hasRole() checks if the principal is instanceof GenericPrincipal
and if not it fails immediately.

Note: previous versions of JAASRealm had their own hasRole() implementation.

Note: request.isUserInRole() is not getting userPrincipal from
GenericPrincipal when calling realm.hasRole() and this one seems to

work.


星期六, 九月 06, 2008

JBOSS JAAS和tomcat j_security_check CMS关系

JAAS是JAVA强大的安全框架模型,JBOSS 对其的支持也是完全和强劲的。

但JAAS总体来说是基于组件的AAA体系(Authentication(验证) Authorization(授权) Accounting(审计)).

Web应用中,往往是基于角色的安全控制(RBAC Role-Based Access Control)比较多,往往授权关系是树形的和矩阵性的复杂关系。

tomcat实现了一个容器类的范围内的验证系统,也就是所谓的CMS(Container Managed Security),这种方式的好处是比较符合要么全有,

要么全无的安全认证,粒度不如JAAS控制的细致。web.xml通过

<security-constraint>
  <web-resource-collection>

<auth-constraint>

三个标志来控制不同角色访问的内容范围.

JBOSS中支持这两种验证方式,但是就出现了一个比较严重的问题。

两种方式是独立的,有各自的LoginContext上下文,必须通过程序的方式在JAAS模块中对Container来进行验证。JBOSS 4.2.3通过class:

org.jboss.web.tomcat.security.login.WebAuthentication;

来实现了这两者对接。综合了两种方式的有点。

另外一种常见的技术是用login proxy的方式来手工调用jsp让内置的j_security_check起作用来综合JAAS和CMS的有点,这里也加入简单说明

在servlet或JSF的backing bean的action对应的方法中,加入如下语句:
String url="/login.jsp"

        RequestDispatcher  dispatcher = request.getRequestDispatcher(url);
        dispatcher.forward(request, response);
login.jsp包含如下内容:

<html>
    <head>
      <meta
http-equiv="Content-Type"
content="text/html; charset=windows-1252"/>
<title>Logging in</title>
    </head>
      <body
onload="document.forms[0].submit()">
      <form
method="post" action="j_security_check">
<input type="hidden" name="j_username"
value="${param.j_username}"/>
<input type="hidden" name="j_password"
value="${param.j_password}"/>
      </form>
    </body>
  </html>

上面的j_username和j_password都是从上页用户输入后传递过来的

上述的方式比较简陋,所以下面就是程序完全控制的方式。

以一个JSF的完全应用为例子

首先编写:login.jsp

<?xml version="1.0" encoding="UTF-8"?>
<jsp:root version="2.0"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
>
<jsp:directive.page  contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" />
<html>
    <head>
    <meta http-equiv="Content-Type"
            content="text/html; charset=UTF-8"></meta>
        <title>Login Wizard</title>
    </head>
    <body>

<f:view >
        <h:form >
            <h:outputLabel  value="#{SysRes.username}"/><h:inputText value="#{loginManager.userID}" id="j_username" /><br/>
            <h:outputLabel value="#{SysRes.password}"/><h:inputSecret value="#{loginManager.password}" id="j_password" /><br/>
            <h:commandButton id="checkout" value="${SysRes.OK}" action="#{loginManager.loginAction}" />   
        </h:form>
</f:view>
    </body>   
</html> 
</jsp:root>

 

其次配置faces-config.xml这个是默认的配置文件,可以通过在web.xml中定义改变之,后面举例

<managed-bean>
<managed-bean-name>loginManager</managed-bean-name>
<managed-bean-class>org.security.login.LoginManager</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

 

三:再看managed-bean,代码如下

package org.security.login;

import java.security.Principal;
import java.util.Set;

import javax.faces.application.Application;
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.security.auth.login.LoginContext;
import javax.security.auth.callback.CallbackHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import javax.faces.event.ActionEvent;

import javax.security.auth.Subject ;
import javax.servlet.RequestDispatcher;

import org.jboss.security.SimplePrincipal;
import org.jboss.web.tomcat.security.login.WebAuthentication;
import org.security.login.jass.*;

public class LoginManager
{
       private String _uid = "";
        private String _pwd = "";
         private String requestURI="";
        public String getUserID() { return _uid; }
        public void setUserID(String uid) { _uid = uid; }
        public String getPassword() { return _pwd; }
        public void setPassword(String pwd) { _pwd = pwd; }
        public String loginAction() throws Exception
        {
            FacesContext context = FacesContext.getCurrentInstance();
            HttpServletResponse response =
            (HttpServletResponse) context.getExternalContext().getResponse();
            HttpServletRequest request =
                (HttpServletRequest) context.getExternalContext().getRequest();           
        String securityDomain = "seamAC";//安全区域,在logic-config.xml中定义
        CallbackHandler callbackHandler = new StandardCallbackHandler(getUserID(),getPassword());
        try
        {
            LoginContext lc =
            new LoginContext( securityDomain,
                      callbackHandler );
            lc.login();
            WebAuthentication pwl = new WebAuthentication();
            boolean flag=pwl.login(getUserID(),getPassword());
            System.out.println("WebAuthentication is?"+flag);
            System.out.println("User Principal="+request.getUserPrincipal());
        }
        catch ( Exception e )
        {
            e.printStackTrace();
//            FacesContext context = FacesContext.getCurrentInstance();
//            HttpServletResponse response =
//            (HttpServletResponse) context.getExternalContext().getResponse();
//            response.sendError(100);
//            context.responseComplete();
           // FacesContext.getCurrentInstance().addMessage("checkout",new FacesMessage(e.getMessage()));
//            throw e;
            return "loginFail";
        }
        String url=request.getHeader("referer");
        String cUrl=request.getRequestURI();
        //再次获取
        request =(HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();       
        System.out.println("referer:"+url+" curl:"+cUrl);
        System.out.println("用户角色sysAdmin:"+request.isUserInRole("sysAdmin"));
        System.out.println("用户角色guest:"+request.isUserInRole("guest"));

//        Principal principal = new SimplePrincipal(getUserID());
//        ObjectName jaasMgr = new ObjectName("jboss.security:service=JaasSecurityManager");
//        Object[] params = { securityDomain, principal };
//        String[] signature = { "java.lang.String", Principal.class.getName() };
//        MBeanServer server = (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);
//        server.invoke(jaasMgr, "flushAuthenticationCache", params, signature);
        if(!(url==null ||url.trim().equals("")))
        {   
            String host=request.getHeader("host");
            String cpath=request.getContextPath();
            url=url.replace("http://"+host+cpath,"");
            System.out.println("url now:"+url+" cpath:"+cpath);           
                response.sendRedirect(cpath+"/"+url);   
        //use j_security_check proxy tech,j_username,j_password
//        RequestDispatcher  dispatcher = request.getRequestDispatcher(url);
//        dispatcher.forward(request, response);
        }       
        return "loginPass";   
        }
        public void logout(){
            FacesContext fc = javax.faces.context.FacesContext.getCurrentInstance();
            ((HttpSession)fc.getExternalContext().getSession(false)).invalidate();
            Application ap = fc.getApplication();
            NavigationHandler nh = ap.getNavigationHandler();
            nh.handleNavigation(fc,null,"logout");
        }

}

 

四:配置web.xml 加入受保护的资源

<!-- 安全部分的配置 -->
<security-constraint>
  <web-resource-collection>
   <web-resource-name>Secure Pages</web-resource-name>
   <url-pattern>/Genesis/*</url-pattern>
   <url-pattern>/Guest/*</url-pattern>  
   <http-method>GET</http-method>
   <http-method>POST</http-method>
   <!-- http-method>HEAD</http-method>
   <http-method>PUT</http-method>
   <http-method>OPTIONS</http-method>
   <http-method>TRACE</http-method>
   <http-method>DELETE</http-method -->
  </web-resource-collection>
<!-- only Admin role can access -->
  <auth-constraint>
<role-name>sysAdmin</role-name>
  </auth-constraint>

</security-constraint>

<!-- 登录验证方式 -->
<login-config>
  <auth-method>FORM</auth-method>
  <realm-name>seamAC</realm-name>
  <form-login-config>
   <form-login-page>/Login.jsp</form-login-page>
   <form-error-page>/Login.jsp</form-error-page>
  </form-login-config>
</login-config>
<!-- Declare all Role List -->
<security-role>
  <role-name>sysAdmin</role-name>
</security-role>
  <security-role>
  <role-name>sysGuest</role-name> 
</security-role>

五:配置jboss相关部分.使用Jboss 4.2.3 GA JDK1.6 update 10
   JAAS部分:conf/login-config.xml,注意seamAC就是LoginManager class中的login方法中引用的,Realm名字.

<!--JAAS  -->
    <application-policy name = "seamAC">
       <authentication>
          <login-module code = "org.jboss.security.auth.spi.DatabaseServerLoginModule"
             flag = "required">
             <module-option name = "unauthenticatedIdentity">guest</module-option>
             <module-option name = "dsJndiName">java:/SecMasterDS</module-option>
             <module-option name = "principalsQuery">select password from sysUser where userid=? </module-option>
             <module-option name = "rolesQuery">SELECT A.roleID as Role,'Roles' FROM sysRoles A,UserRoles B WHERE A.roleID=B.roleID AND B.userId=?</module-option>
             <module-option name = "debug">true</module-option>
<!--Password is md5 encrypt-->
                        <module-option name="hashAlgorithm">MD5</module-option>
            <module-option name ="hashEncoding">HEX</module-option>
          </login-module>
       </authentication>
    </application-policy>

注意:rolesQuery部分,根据Jboss的class org/jboss/security/auth/spi/DatabaseServerLoginModule.java中有关角色部分的说明,必须有一个roleGroup的字段值为Roles,否则出现用户没有角色的错误,小心注意,这是很愚蠢的假定,往往配置了很久,不能工作,就是这些小地方。

  141   /** Overriden by subclasses to return the Groups that correspond to the
142   to the role sets assigned to the user. Subclasses should create at
143   least a Group named "Roles" that contains the roles assigned to the user.
144   A second common group is "CallerPrincipal" that provides the application
145   identity of the user rather than the security domain identity.
146   @return Group[] containing the sets of roles
147   */

数据库部分:deploy/mysql-ds.xml(使用MYSQL 5.1),注意SecMasterDS



<local-tx-datasource>
   <jndi-name>SecMasterDS</jndi-name>
   <connection-url>jdbc:mysql://localhost:3306/gate?useUnicode=TRUE</connection-url>
   <driver-class>com.mysql.jdbc.Driver</driver-class>
   <user-name>root</user-name>
   <password></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>

 


支持,繁琐的配置终于可以工作了,访问一个目录,然后经过验证,显示出来内容,实在是非常惬意的事情。更加人性化的界面,比如不具有权限的人向访问一个特定角色的资源,可以在web.xml中截获403错误来做到:



< error-page>
  <error-code>403</error-code>
  <location>/roleerror.jsp</location>
</error-page>

JBOSS JAAS 同JSF 相关问题

如果出现验证后出现,isUserInRole返回false的情况
首先打开
conf/jboss-log4j.xml 的debug.


http://wiki.jboss.org/wiki/SecurityFAQ

<!--Debug log login sql -->
<category name="org.jboss.security">
<priority value="TRACE" class="org.jboss.logging.XLevel"/>
</category>
<category name="org.jboss.web.tomcat.security">
<priority value="TRACE" class="org.jboss.logging.XLevel"/>
</category>
<category name="org.apache.catalina">
<priority value="DEBUG"/>
</category>

星期五, 九月 05, 2008

JSF 或JSP EL(Express Language)中的变量

在JSF和JSP中,EL引用一个变量,语法如下#{class.fieldName}或${class.fieldName}
这里fieldName必须是首字母小写的,但对应的class的方法名为getFieldName()
这种奇怪的语法是来自类 java.beans.PropertyDescriptor 的构造函数规定的
PropertyDescriptor

public PropertyDescriptor(String propertyName,
Class beanClass) throws IntrospectionException

为某特性构造 PropertyDescriptor ,它通过拥有 getFoo 和 setFoo 访问者来遵循标准 Java 约定。因此若参数名是“fred”,则假定读程序方法是“getFred”并且写程序方法是“setFred”。注意特性名应以小写字符开始, 它将在方法名中被大写化。

Note that the property name should start with a lower case character, which will be capitalized in the method names.

星期五, 八月 15, 2008

JSON-Lib版本检查

JSON-Lib是套开源的 JSON库,
目前2.2.x系列是基本没有错误的版本。
1.1系列的问题很大,主要是 不能保存原始数据解析顺序的问题。

本来想寻找版本的信息。但没有发现,不过2.2增加了net.sf.json.JsonConfig类,1.1.x序列的没有
所以可以在代码中加上检查

public static Boolean checkJSONLibVersion()
{
try
{
Class.forName("net.sf.json.JsonConfig",false,ClassLoader.getSystemClassLoader());
}catch(ClassNotFoundException e)
{
return false;//1.1.x版本,解析数据顺序不对。
}
return true; //2.2.x版本
}

星期四, 八月 14, 2008

BLOGGER竟然有一个比较好的来显示代码的tag

blogger内置的标签:

blockquote

only a test
test for what

星期二, 八月 12, 2008

JBOSS 4.2.1 打开Log Trace 开关

1.conf/login-config.xml

加入:

<category name="org.jboss.security">
   <priority value="TRACE"/>
</category>
<category name="org.jboss.web.tomcat.security">
   <priority value="TRACE"/>
</category>
<category name="org.apache.catalina">
   <priority value="TRACE"/>
</category>

2.conf/jboss-log4j.xml,修改system.out Logger

<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
   <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
   <param name="Target" value="System.out"/>
   <param name="Threshold" value="TRACE"/>

   <layout class="org.apache.log4j.PatternLayout">
      <!-- The default pattern: Date Priority [Category] Message\n -->
      <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
   </layout>
</appender>

星期六, 八月 09, 2008

JAAS:灵活的Java安全机制

John Musser/Paul Feuer著 冯睿编译

ava Authentication Authorization Service(JAAS,Java验证和授权API)提供了灵活和可伸缩的机制来保证客户端或服务器端的Java程序。Java早期的安全框架强调的是通过验证代码的来源和作者,保护用户避免受到下载下来的代码的攻击。JAAS强调的是通过验证谁在运行代码以及他/她的权限来保护系统面受用户的攻击。它让你能够将一些标准的安全机制,例如Solaris NIS(网络信息服务)、Windows NT、LDAP(轻量目录存取协议),Kerberos等通过一种通用的,可配置的方式集成到系统中。本文首先向你介绍JAAS验证中的一些核心部分,然后通过例子向你展示如何开发登录模块。
你是否曾经需要为一个应用程序实现登录模块呢?如果你是一个比较有经验的程序员,相信你这样的工作做过很多次,而且每次都不完全一样。你有可能把你的登录模块建立在Oracle数据库的基础上,也有可能使用的是NT的用户验证,或者使用的是 LDAP目录。如果有一种方法可以在不改变应用程序级的代码的基础上支持上面提到的所有这一些安全机制,对于程序员来说一定是一件幸运的事。
现在你可以使用JAAS实现上面的目标。JAAS是一个比较新的的Java API。在J2SE 1.3中,它是一个扩展包;在J2SE 1.4中变成了一个核心包。在本文中,我们将介绍JAAS的一些核心概念,然后通过例子说明如何将JAAS应用到实际的程序中。本文的例子是根据我们一个基于Web的Java应用程序进行改编的,在这个例子中,我们使用了关系数据库保存用户的登录信息。由于使用了JAAS,我们实现了一个健壮而灵活的登录和身份验证模块。
Java验证和授权:概论
在JAAS出现以前,Java的安全模型是为了满足跨平台的网络应用程序的需要而设计的。在Java早期版本中,Java通常是作为远程代码被使用,例如Applet,。因此最初的安全模型把注意力放在通过验证代码的来源来保护用户上。早期的Java安全机制中包含的概念,如 SercurityManager,沙箱概念,代码签名,策略文件,多是为了保护用户。
JAAS的出现反映了Java的演变。传统的服务器/客户端程序需要实现登录和存取控制,JAAS通过对运行程序的用户的进行验证,从而达到保护系统的目的。虽然JAAS同时具有验证和授权的能力,在这篇文章中,我们主要介绍验证功能。
通过在应用程序和底层的验证和授权机制之间加入一个抽象层,JAAS可以简化涉及到Java Security包的程序开发。抽象层独立于平台的特性使开发人员可以使用各种不同的安全机制,而且不用修改应用程序级的代码。和其他Java Security API相似,JAAS通过一个可扩展的框架:服务提供者接口(Service Provider Interface,SPI)来保证程序独立于安全机制。服务提供者接口是由一组抽象类和接口组成的。图一中给出了JAAS程序的整体框架图。应用程序级的代码主要处理LoginContext。在LoginContext下面是一组动态配置的LoginModules。LoginModule使用正确的安全机制进行验证。
图一给出了JAAS的概览。应用程序层的代码只需要和LoginContext打交道。在LoginContext之下是一组动态配置的LoginModule对象,这些对象使用相关的安全基础结构进行验证操作。

 jt-2003-1-14-image001

                                               图一 JAAS概览

JAAS提供了一些LoginModule的参考实现代码,比如JndiLoginModule。开发人员也可以自己实现LoginModule接口,就象在我们例子中的RdbmsLonginModule。同时我们还会告诉你如何使用一个简单的配置文件来安装应用程序。
为了满足可插接性,JAAS是可堆叠的。在单一登录的情况下,一组安全模块可以堆叠在一起,然后被其他的安全机制按照堆叠的顺序被调用。
JAAS的实现者根据现在一些流行的安全结构模式和框架将JASS模型化。例如可堆叠的特性同Unix下的可堆叠验证模块(PAM,Pluggable Authentication Module)框架就非常相似。从事务的角度看,JAAS类似于双步提交(Two-Phase Commit,2PC)协议的行为。JAAS中安全配置的概念(包括策略文件(Police File)和许可(Permission))来自于J2SE 1.2。JAAS还从其他成熟的安全框架中借鉴了许多思想。

 

客户端和服务器端的JAAS

开发人员可以将JAAS应用到客户端和服务器端。在客户端使用JAAS很简单。在服务器端使用JAAS时情况要复杂一些。目前在应用服务器市场中的 JAAS产品还不是很一致,使用JAAS的J2EE应用服务器有一些细微的差别。例如JBossSx使用自己的结构,将JAAS集成到了一个更大的安全框架中;而虽然WebLogic 6.x也使用了JAAS,安全框架却完全不一样。

现在你能够理解为什么我们需要从客户端和服务器端的角度来看JAAS了。我们将在后面列出两种情况下的例子。为了使服务器端的例子程序更加简单,我们使用了Resin应用服务器。

核心JAAS类

在使用JAAS之前,你首先需要安装JAAS。在J2SE 1.4中已经包括了JAAS,但是在J2SE 1.3中没有。如果你希望使用J2SE 1.3,你可以从SUN的官方站点上下载JAAS。当正确安装了JAAS后,你会在安装目录的lib目录下找到jaas.jar。你需要将该路径加入 Classpath中。(注:如果你安装了应用服务器,其中就已经包括了JAAS,请阅读应用服务器的帮助文档以获得更详细的信息)。在Java安全属性文件java.security中,你可以改变一些与JAAS相关的系统属性。该文件保存在<jre_home>/lib/security目录中。

在应用程序中使用JAAS验证通常会涉及到以下几个步骤:

1. 创建一个LoginContext的实例。

2. 为了能够获得和处理验证信息,将一个CallBackHandler对象作为参数传送给LoginContext。

3. 通过调用LoginContext的login()方法来进行验证。

4. 通过使用login()方法返回的Subject对象实现一些特殊的功能(假设登录成功)。

下面是一个简单的例子:

LoginContext lc = new LoginContext("MyExample");
try {
lc.login();
} catch (LoginException) {
// Authentication failed.
}

// Authentication successful, we can now continue.
// We can use the returned Subject if we like.
Subject sub = lc.getSubject();
Subject.doAs(sub, new MyPrivilegedAction());


在运行这段代码时,后台进行了以下的工作。

1. 当初始化时,LoginContext对象首先在JAAS配置文件中找到MyExample项,然后更具该项的内容决定该加载哪个LoginModule对象(参见图二)。

2. 在登录时,LoginContext对象调用每个LoginModule对象的login()方法。

3. 每个login()方法进行验证操作或获得一个CallbackHandle对象。

4. CallbackHandle对象通过使用一个或多个CallBack方法同用户进行交互,获得用户输入。

5. 向一个新的Subject对象中填入验证信息。

我们将对代码作进一步的解释。但是在这之前,让我们先看代码中涉及到的核心JAAS类和接口。这些类可以被分为三种类型:

普通类型 Subject,Principal,凭证

验证 LoginContext,LoginModule,CallBackHandler,Callback

授权 Policy,AuthPermission,PrivateCredentialPermission

上面列举的类和接口大多数都在javax.security.auth包中。在J2SE 1.4中,还有一些接口的实现类在com.sun.security.auth包中。

普通类型:Subject,Principal,凭证

Subject类代表了一个验证实体,它可以是用户、管理员、Web服务,设备或者其他的过程。该类包含了三中类型的安全信息:

身份(Identities):由一个或多个Principal对象表示

公共凭证(Public credentials):例如名称或公共秘钥

私有凭证(Private credentials):例如口令或私有密钥

Principal对象代表了Subject对象的身份。它们实现了java.security.Principal和 java.io.Serializable接口。在Subject类中,最重要的方法是getName()。该方法返回一个身份名称。在Subject对象中包含了多个Principal对象,因此它可以拥有多个名称。由于登录名称、身份证号和Email地址都可以作为用户的身份标识,可见拥有多个身份名称的情况在实际应用中是非常普遍的情况。

在上面提到的凭证并不是一个特定的类或借口,它可以是任何对象。凭证中可以包含任何特定安全系统需要的验证信息,例如标签(ticket),密钥或口令。Subject对象中维护着一组特定的私有和公有的凭证,这些凭证可以通过 getPrivateCredentials()和getPublicCredentials()方法获得。这些方法通常在应用程序层中的安全子系统被调用。

验证:LoginContext

在应用程序层中,你可以使用LoginContext对象来验证Subject对象。LoginContext对象同时体现了JAAS的动态可插入性(Dynamic Pluggability),因为当你创建一个LoginContext的实例时,你需要指定一个配置。LoginContext通常从一个文本文件中加载配置信息,这些配置信息告诉LoginContext对象在登录时使用哪一个LoginModule对象。

下面列出了在LoginContext中经常使用的三个方法:

login () 进行登录操作。该方法激活了配置中制定的所有LoginModule对象。如果成功,它将创建一个经过了验证的Subject对象;否则抛出LoginException异常。

getSubject () 返回经过验证的Subject对象

logout () 注销Subject对象,删除与之相关的Principal对象和凭证

验证:LoginModule

LoginModule是调用特定验证机制的接口。J2EE 1.4中包含了下面几种LoginModule的实现类:

JndiLoginModule 用于验证在JNDI中配置的目录服务

Krb5LoginModule 使用Kerberos协议进行验证

NTLoginModul 使用当前用户在NT中的用户信息进行验证

UnixLoginModule 使用当前用户在Unix中的用户信息进行验证

同上面这些模块绑定在一起的还有对应的Principal接口的实现类,例如NTDomainPrincipal和UnixPrincipal。这些类在com.sun.security.auth包中。

LoginModule接口中包含了五个方法:

initialize () 当创建一LoginModule实例时会被构造函数调用

login () 进行验证

commit () 当LgoninContext对象接受所有LoginModule对象传回的结果后将调用该方法。该方法将Principal对象和凭证赋给Subject对象。

abort () 当任何一个LoginModule对象验证失败时都会调用该方法。此时没有任何Principal对象或凭证关联到Subject对象上。

logout () 删除与Subject对象关联的Principal对象和凭证。

在应用程序的代码中,程序员通常不会直接调用上面列出的方法,而是通过LigonContext间接调用这些方法。

验证:CallbackHandler和Callback

CallbackHandler和Callback对象可以使LoginModule对象从系统和用户那里收集必要的验证信息,同时独立于实际的收集信息时发生的交互过程。

JAAS在javax.sevurity.auth.callback包中包含了七个Callback的实现类和两个CallbackHandler的实现类:ChoiceCallback、ConfirmationCallback、LogcaleCallback、NameCallback、 PasswordCallback、TextInputCallback、TextOutputCallback、 DialogCallbackHandler和TextCallBackHandler。Callback接口只会在客户端会被使用到。我将在后面介绍如何编写你自己的CallbackHandler类。

配置文件

上面我已经提到,JAAS的可扩展性来源于它能够进行动态配置,而配置信息通常是保存在文本。这些文本文件有很多个配置块构成,我们通常把这些配置块称作申请(Application)。每个申请对应了一个或多个特定的LoginModule对象。

当你的代码构造一个LoginContext对象时,你需要把配置文件中申请的名称传递给它。LoginContext将会根据申请中的信息决定激活哪些LoginModule对象,按照什么顺序激活以及使用什么规则激活。

配置文件的结构如下所示:

Application {
ModuleClass Flag ModuleOptions;
ModuleClass Flag ModuleOptions;
...
};
Application {
ModuleClass Flag ModuleOptions;
...
};
...

下面是一个名称为Sample的申请

Sample {
com.sun.security.auth.module.NTLoginModule Rquired debug=true;
}


上面这个简单的申请指定了LoginContext对象应该使用NTLoginModule进行验证。类的名称在ModuleClass中被指定。 Flag控制当申请中包含了多个LoginModule时进行登录时的行为:Required、Sufficient、Requisite和 Optional。最常用的是Required,使用它意味着对应的LoginModule对象必须被调用,并且必须需要通过所有的验证。由于Flag本身的复杂性,本文在这里不作深究。

ModuleOption允许有多个参数。例如你可以设定调试参数为True(debug=true),这样诊断输出将被送到System.out中。

配置文件可以被任意命名,并且可以被放在任何位置。JAAS框架通过使用java.securty.auth.long.config属性来确定配置文件的位置。例如当你的应用程序是JaasTest,配置文件是当前目录下的jaas.config,你需要在命令行中输入:

java -Djava.security.auth.login.config=jass.config JavaTest

图二描述了配置文件中各元素之间的关系

 jt-2003-1-14-image002

                    图二 JAAS的配置文件

通过命令行方式进行登录验证

为了说明JAAS到底能干什么,我在这里编写了两个例子。一个是简单的由命令行输入调用的程序,另一个是服务器端的JSP程序。这两个程序都通过用户名/密码的方式进行登录,然后使用关系数据库对其进行验证。

为了通过数据库进行验证,我们需要:

1. 实现RdbmsLoginModul类,该类可以对输入的信息进行验证。

2. 编辑一个配置文件,告诉LoginContext如何使用RdbmsLoginModule。

3. 实现ConsoleCallbackHandler类,通过该类可以获取用户的输入。

4. 编写应用程序代码。

在RdbmsLoginModul类中,我们必须实现LgoinModule接口中的五个方法。首先是initialize()方法:

public void initialize(Subject subject, CallbackHandler
callbackHandler,

Map sharedState, Map options)
{
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;

url = (String)options.get("url");
driverClass = (String)options.get("driver");
debug = "true".equalsIgnoreCase((String)options.get("debug"));
}

LoginContext在调用login()方法时会调用initialize()方法。RdbmsLoginModule的第一个任务就是在类中保存输入参数的引用。在验证成功后将向Subject对象中送入Principal对象和凭证。

CallbackHandler对象将会在login()方法中被使用到。sharedState可以使数据在不同的LoginModule对象之间共享,但是在这个例子中我们不会使用它。最后是名为options的Map对象。options向LgoinModule对象传递在配置文件 ModuleOption域中定义的参数的值。配置文件如下所示:

Example {
RdbmsLoginModule required
driver="org.gjt.mm.mysql.Driver"
url="jdbc:mysql://localhost/jaasdb?user=root"
debug="true";
};

在配置文件中,RdbmsLoginModule包含了五个参数,其中driver、url、user和password是必需的,而debug是可选阐述。driver、url、user和password参数告诉我们如何获得JDBC连接。当然你还可以在ModuleOption域中加入数据库中的表或列的信息。使用这些参数的目的是为了能够对数据库进行操作。在LoginModule类的initialize()方法中我们保存了每个参数的值。

我们前面提到一个LoginContext对应的配置文件告诉它应该使用文件中的哪一个申请。这个信息是通过LgoinContext的构造函数传递的。下面是初始化客户端的代码,在代码中创建了一个LoginContex对象并调用了login()方法。

ConsoleCallbackHandler cbh = new ConsoleCallbackHandler();
LoginContext lc = new LoginContext("Example", cbh);
lc.login();

当LgoinContext.login()方法被调用时,它调用所有加载了的LoginModule对象的login()方法。在我们的这个例子中是RdbmsLoginModule中的login()方法。

RdbmsLoginModule中的login()方法进行了下面的操作:

1. 创建两个Callback对象。这些对象从用户输入中获取用户名/密码。程序中使用了JAAS中的两个Callback类:NameCallback和 PasswordCallback(这两个类包含在javax.security.auth.callback包中)。

2. 通过将callbacks作为参数传递给CallbackHandler的handle()方法来激活Callback。

3. 通过Callback对象获得用户名/密码。

4. 在rdbmsValidate()方法中通过JDBC在数据库中验证获取的用户名/密码。

下面是RdbmsLoginModule中的login()方法的代码

public boolean login() throws LoginException {
if (callbackHandler == null)
throw new LoginException("no handler");

NameCallback nameCb = new NameCallback("user: ");
PasswordCallback passCb = new PasswordCallback("password: ", true);
callbacks = new Callback[] { nameCb, passCb };
callbackHandler.handle(callbacks);

String username = nameCb.getName();
String password = new String(passCb.getPassword());
success = rdbmsValidate(username, password);

return(true);
}

在ConsoleCallbackHandler类的handle()方法中你可以看到Callback对象是如何同用户进行交互的:

public void handle(Callback[] callbacks)
throws java.io.IOException, UnsupportedCallbackException {

for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
NameCallback nameCb = (NameCallback)callbacks[i];
System.out.print(nameCb.getPrompt());
String user=(new BufferedReader(new

InputStreamReader(System.in))).readLine();
nameCb.setName(user);
} else if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback passCb = (PasswordCallback)callbacks[i];
System.out.print(passCb.getPrompt());
String pass=(new BufferedReader(new

InputStreamReader(System.in))).readLine();
passCb.setPassword(pass.toCharArray());
} else {
throw(new UnsupportedCallbackException(callbacks[i],
"Callback class not supported"));
}
}
}

Post By Windows Live Writer

Work or not.

星期四, 八月 07, 2008

JSF无限递归错误Infinite recursion

运行.jsf文件,后台出现解析无线递归错误。最后出现
java.lang.StackOverflowError

错误原因在于同时声明了
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.jsf</param-value>
</context-param>


<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>


只要去掉 javax.faces.DEFAULT_SUFFIX的申明就解决问题了

JSF 访问控制Access Control方法

1.思路,扩展JSF提供的JAAS验证和Navigator 来定制满足自己要求的方法

JSF对安全的支持,是通过web.xml里JAAS相关申明和faces-config.xml里的导航规则说明,
以及在jsp或JSF页面里的相关 rendered标志的控制来做到。
也是 一个MVC的结构.
A.扩展自己的class (Control)
B.配置文件声明(web.xml,faces-config.xml) (Model)
C.jsp或JSF页面里的引用. (View)

web.xml里申明使用的导航配置文件,可以指定多个,用逗号,分开不同的配置文件。除了默认的faces-config.xml意外。
web.xml:
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml,/WEB-INF/faces-beans.xml</param-value>
</context-param>
一个技巧,定义一个网站或一个目录使用的导航规则,使用符号"*",如下
<navigation-rule> </navigation-rule>                        
<from-view-id>*</from-view-id>
<navigation-case> </navigation-case>
<from-outcome>globalhelp</from-outcome>
<to-view-id>/menu/generalHelp.jsp</to-view-id>



在JSP页面使用在faces-config.xml里定义的导航规则:
首先定义一个导航规则:
<navigation-rule>
<from-view-id>/pages/inputname.jsp</from-view-id>
<navigation-case>
<from-outcome><span style="font-weight: bold; color: rgb(255, 0, 0);">sayHello</span></from-outcome>
<to-view-id>/pages/anotherhello.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{GetNameBean.helloAction}</from-action>
<from-outcome>sayHello</from-outcome>
<to-view-id>/pages/hello.jsp</to-view-id>
</navigation-case>

</navigation-rule>

<h:commandbutton id="submit" action="sayHello" value="Submit">
sayHello就是在faces-config.xml里定义的。

http://sunxacml.sourceforge.net/faq.html
http://www.oasis-open.org/committees/xacml/

星期三, 八月 06, 2008

.JSF 使用及其他。

指定JSF pageEncoding必须使用:

在JSF文件第一行申明,用jsp的<%@page pageEncoding="UTF-8">来申明将会出现运行时间的

jsf The markup in the document preceding the root element must be well-formed

错误。

如果想区别jsp和jsf文件,让后缀为.jsf的文件直接用faceservlet来解析。需要在web.xml加入以下两组配置

1.修改默认的jsf文件默认后缀.
<context-param></context-param></span>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.jsf</param-value></span>


2.修改触发pattern
<servlet></servlet>
<servlet-name>Faces Servlet
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>


<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>


这样在浏览器里敲入http://localhost:8080/gate/index.jsf 就可以直接看到结果了。

Java数据库设计中的14个技巧

Java数据库设计中的14个技巧

http://news.newhua.com/news1/programming/2008/48/0848108471BJ3B21FAIB3C4G26JDJ3CB4436K58EG52EC9234IIKH3_3.html


下述十四个技巧,是许多人在大量的数据库分析与设计实践中,逐步总结出来的。对于这些经验的运用,读者不能生帮硬套,死记硬背,而要消化理解,实事求是,灵活掌握。并逐步做到:在应用中发展,在发展中应用。

1. 原始单据与实体之间的关系
  
可以是一对一、一对多、多对多的关系。在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体。在特殊情况下,它们可能是一对多或多对一 的关系,即一张原始单证对应多个实体,或多张原始单证对应一个实体。这里的实体可以理解为基本表。明确这种对应关系后,对我们设计录入界面大有好处。

〖例1〗:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表、社会关系表、工作简历表。这就是“一张原始单证对应多个实体”的典型例子。


2. 主键与外键
  
一般而言,一个实体不能既无主键又无外键。在E?R 图中, 处于叶子部位的实体, 可以定义主键,也可以不定义主键(因为它无子孙), 但必须要有外键(因为它有父亲)。
  
主键与外键的设计,在全局数据库的设计中,占有重要地位。当全局数据库的设计完成以后,有个美国数据库设计专家说:“键,到处都是键,除了键之外,什么也 没有”,这就是他的数据库设计经验之谈,也反映了他对信息系统核心(数据模型)的高度抽象思想。因为:主键是实体的高度抽象,主键与外键的配对,表示实体 之间的连接。


3. 基本表的性质
  
基本表与中间表、临时表不同,因为它具有如下四个特性:
  
(1) 原子性。基本表中的字段是不可再分解的。
   (2) 原始性。基本表中的记录是原始数据(基础数据)的记录。
   (3) 演绎性。由基本表与代码表中的数据,可以派生出所有的输出数据。
   (4) 稳定性。基本表的结构是相对稳定的,表中的记录是要长期保存的。

理解基本表的性质后,在设计数据库时,就能将基本表与中间表、临时表区分开来。


4. 范式标准
 
基本表及其字段之间的关系, 应尽量满足第三范式。但是,满足第三范式的数据库设计,往往不是最好的设计。为了提高数据库的运行效率,常常需要降低范式标准:适当增加冗余,达到以空间换时间的目的。

〖例2〗:有一张存放商品的基本表,如表1所示。“金额”这个字段的存在,表明该表的设计不满足第三范式,因为“金额”可以由“单价”乘以“数量”得到,说明“金额”是冗余字段。但是,增加“金额”这个冗余字段,可以提高查询统计的速度,这就是以空间换时间的作法。
  
在Rose 2002中,规定列有两种类型:数据列和计算列。“金额”这样的列被称为“计算列”,而“单价”和“数量”这样的列被称为“数据列”。
  
表1 商品表的表结构
   商品名称 商品型号 单价 数量 金额
   电视机 29? 2,500 40 100,000

  
5. 通俗地理解三个范式
  
通俗地理解三个范式,对于数据库设计大有好处。在数据库设计中,为了更好地应用三个范式,就必须通俗地理解三个范式(通俗地理解是够用的理解,并不是最科学最准确的理解):
  
  1. 第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解;
  2.    第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;
  3.    第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余.
  
没有冗余的数据库设计可以做到。但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是:在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字
,允许冗余。

6. 要善于识别与正确处理多对多的关系

若两个实体之间存在多对多的关系,则应消除这种关系。消除的办法是,在两者之间增加第三个实体。这样,原来一个多对多的关系,现在变为两个一对多的关系。 要将原来两个实体的属性合理地分配到三个实体中去。这里的第三个实体,实质上是一个较复杂的关系,它对应一张基本表。一般来讲,数据库设计工具不能识别多 对多的关系,但能处理多对多的关系。

〖例3〗:在“图书馆信息系统”中,“图书”是一个实体,“读者”也是一个实体。这两个实体之间的关系,是一个典型的多对多关系:一本图书在不同时间可以 被多个读者借阅,一个读者又可以借多本图书。为此,要在二者之间增加第三个实体,该实体取名为“借还书”,它的属性为:借还时间、借还标志(0表示借 书,1表示还书),另外,它还应该有两个外键(“图书”的主键,“读者”的主键),使它能与“图书”和“读者”连接。

7. 主键PK的取值方法
  
PK是供程序员使用的表间连接工具,可以是一无物理意义的数字串, 由程序自动加1来实现。也可以是有物理意义的字段名或字段名的组合。不过前者比后者好。当PK是字段名的组合时,建议字段的个数不要太多,多了不但索引占用空间大,而且速度也慢。

8. 正确认识数据冗余
  
主键与外键在多表中的重复出现, 不属于数据冗余,这个概念必须清楚,事实上有许多人还不清楚。非键字段的重复出现, 才是数据冗余!而且是一种低级冗余,即重复性的冗余。高级冗余不是字段的重复出现,而是字段的派生出现。

〖例4〗:商品中的“单价、数量、金额”三个字段,“金额”就是由“单价”乘以“数量”派生出来的,它就是冗余,而且是一种高级冗余。冗余的目的是为了提 高处理速度。只有低级冗余才会增加数据的不一致性,因为同一数据,可能从不同时间、地点、角色上多次录入。因此,我们提倡高级冗余(派生性冗余),反对低 级冗余(重复性冗余)。

9. E--R图没有标准答案
  
信息系统的E--R图没有标准答案,因为它的设计与画法不是惟一的,只要它覆盖了系统需求的业务范围和功能内容,就是可行的。反之要修改E--R图。尽管 它没有惟一的标准答案,并不意味着可以随意设计。好的E?R图的标准是:结构清晰、关联简洁、实体个数适中、属性分配合理、没有低级冗余。

10. 视图技术在数据库设计中很有用
  
与基本表、代码表、中间表不同,视图是一种虚表,它依赖数据源的实表而存在。视图是供程序员使用数据库的一个窗口,是基表数据综合的一种形式, 是数据处理的一种方法,是用户数据保密的一种手段。为了进行复杂处理、提高运算速度和节省存储空间, 视图的定义深度一般不得超过三层。 若三层视图仍不够用, 则应在视图上定义临时表, 在临时表上再定义视图。这样反复交迭定义, 视图的深度就不受限制了。

对于某些与国家政治、经济、技术、军事和安全利益有关的信息系统,视图的作用更加重要。这些系统的基本表完成物理设计之后,立即在基本表上建立第一层视 图,这层视图的个数和结构,与基本表的个数和结构是完全相同。并且规定,所有的程序员,一律只准在视图上操作。只有数据库管理员,带着多个人员共同掌握的 “安全钥匙”,才能直接在基本表上操作。请读者想想:这是为什么?

11. 中间表、报表和临时表
  
中间表是存放统计数据的表,它是为数据仓库、输出报表或查询结果而设计的,有时它没有主键与外键(数据仓库除外)。临时表是程序员个人设计的,存放临时记录,为个人所用。基表和中间表由DBA维护,临时表由程序员自己用程序自动维护。

12. 完整性约束表现在三个方面

  
域的完整性:用Check来实现约束,在数据库设计工具中,对字段的取值范围进行定义时,有一个Check按钮,通过它定义字段的值城。参照完整性:用PK、FK、表级触发器来实现。用户定义完整性:它是一些业务规则,用存储过程和触发器来实现。

13. 防止数据库设计打补丁的方法是“三少原则”
  
(1) 一个数据库中表的个数越少越好。只有表的个数少了,才能说明系统的E--R图少而精,去掉了重复的多余的实体,形成了对客观世界的高度抽象,进行了系统的数据集成,防止了打补丁式的设计;
  
(2) 一个表中组合主键的字段个数越少越好。因为主键的作用,一是建主键索引,二是做为子表的外键,所以组合主键的字段个数少了,不仅节省了运行时间,而且节省了索引存储空间;
  
(3) 一个表中的字段个数越少越好。只有字段的个数少了,才能说明在系统中不存在数据重复,且很少有数据冗余,更重要的是督促读者学会“列变行”,这样就防止了 将子表中的字段拉入到主表中去,在主表中留下许多空余的字段。所谓“列变行”,就是将主表中的一部分内容拉出去,另外单独建一个子表。这个方法很简单,有 的人就是不习惯、不采纳、不执行。
  
数据库设计的实用原则是:在数据冗余和处理速度之间找到合适的平衡点。“三少”是一个整体概念,综合观点,不能孤立某一个原则。该原则是相对的,不是绝对 的。“三多”原则肯定是错误的。试想:若覆盖系统同样的功能,一百个实体(共一千个属性) 的E--R图,肯定比二百个实体(共二千个属性) 的E--R图,要好得多。
  
提倡“三少”原则,是叫读者学会利用数据库设计技术进行系统的数据集成。数据集成的步骤是将文件系统集成为应用数据库,将应用数据库集成为主题数据库,将 主题数据库集成为全局综合数据库。集成的程度越高,数据共享性就越强,信息孤岛现象就越少,整个企业信息系统的全局E?R图中实体的个数、主键的个数、属 性的个数就会越少。
  
提倡“三少”原则的目的,是防止读者利用打补丁技术,不断地对数据库进行增删改,使企业数据库变成了随意设计数据库表的“垃圾堆”,或数据库表的“大杂院 ”,最后造成数据库中的基本表、代码表、中间表、临时表杂乱无章,不计其数,导致企事业单位的信息系统无法维护而瘫痪。
  
“三多”原则任何人都可以做到,该原则是“打补丁方法”设计数据库的歪理学说。“三少”原则是少而精的原则,它要求有较高的数据库设计技巧与艺术,不是任何人都能做到的,因为该原则是杜绝用“打补丁方法”设计数据库的理论依据。

14. 提高数据库运行效率的办法
  
在给定的系统硬件和系统软件条件下,提高数据库系统的运行效率的办法是:
(1) 在数据库物理设计时,降低范式,增加冗余, 少用触发器, 多用存储过程。

(2) 当计算非常复杂、而且记录条数非常巨大时(例如一千万条),复杂计算要先在数据库外面,以文件系统方式用C++语言计算处理完成之后,最后才入库追加到表中去。这是电信计费系统设计的经验。
  
(3) 发现某个表的记录太多,例如超过一千万条,则要对该表进行水平分割。水平分割的做法是,以该表主键PK的某个值为界线,将该表的记录水平分割为两个表。若发现某个表的字段太多,例如超过八十个,则垂直分割该表,将原来的一个表分解为两个表。
  
(4) 对数据库管理系统DBMS进行系统优化,即优化各种系统参数,如缓冲区个数。
  
(5) 在使用面向数据的SQL语言进行程序设计时,尽量采取优化算法。
 
总之,要提高数据库的运行效率,必须从数据库系统级优化、数据库设计级优化、程序实现级优化,这三个层次上同时下功夫。

星期六, 八月 02, 2008

在Java使用JSON对象

JSON :www.json.org 不但是用来传递结构化的数据可以大显身手,也可以在静态的properties或XML数据中显示强大的威力。

由于现在java 5已经内置的支持javascript 引擎(http://www.mozilla.org/rhino/scriptjava.html)
所以可以在Java代码中通过手工编写调用javascrit来解析JSON的数据,
比如类似下面代码:

import javax.script.*;
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
String str = "{'string':'JSON', 'integer': 1, 'double': 2.0, 'boolean': true}";
engine.eval("a="+str);
String values= (String)engine.eval("a.string");
values里面的值为"JSON";

或者使用JSON的java类库来自(http://json-lib.sourceforge.net/)
代码如下:
这里把JSON对象放在Java的Properties里,注意,Java Properties最后一行必须是包含一个空行的独立行,否则最后一个字符将读不到,这可能是个bug或者怪癖吧。 注意下列的多行的写法,
每一行后面加入一个 \ 表示是同一行的内容.

com.test.t.properties文件里包含如下内容
DatabaseURL={\
"First":{"defaultDS":"java:/mysql","securityDS":"java:/secMysql"}, \
"Two":{"defaultDS":"java:/mysqlTwo","securityDS":"java:/secMysql"}, \
"Three":{"defaultDS":"java:/mysqlTHree","securityDS":"java:/secMysql"} \
}

import net.sf.json.*;
import java.util.ResourceBundle;
ResourceBundle t=ResourceBundle.getBundle("com.test.t");
JSONObject a=(JSONObject) JSONSerializer.toJSON( t.getString("DatabaseURL"));
JSONObject b=a.getJSONObject("First");//这是两级对象表示的方法
System.out.println(b.getString("defaultDS"));
打印结果为:java:/mysql

星期五, 八月 01, 2008

干净的安装Eclipse的Plugin

方法
步骤一 。在Eclipse的安装目录下找到links目录,如果没有links目录就建立一个目录
步骤二.用unzip或winrar展开plugin到一个建立的目录下,比如d:\Reponstity目录。
步骤三。在Eclipse的links目录下建立一个后缀为.link的文件。该文件里包含一行记录
path=d:/reponsity

这样,启动Eclipse的时候,就载入该插件了。同样卸载的时候,只需要注释掉path这样一行就可以了。

Seam 开发手册之一,添加新的Seam Runtime

1.新建一个Seam Project时候选择Seam runtime 并且选择Seam 版本(Jboss Web Tools自带) 1.2并且浏览到安装在硬盘上的最新的Seam安装目录the Seam 2.1,但是对话框无法改变Seam 版本字段. 显示一个错误的提示 "The selected seam appears to be of an incompatible version "2.1.0.A1"".
纠正错误的步骤。
1.首先建立新版本的seam

2.修改Project中使用的seam版本。

星期五, 七月 25, 2008

解决Java和Mysql 5.1 jdbc 之间包含汉字的SQL命令无法正常解析问题

Jsp Encode=UTF-->Servlet by jdbc--->mysql 5.1

如果包含汉字需要在jboss mysql-ds.xml里链接字符串加入如下

<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/gpsrm?useUnicode=TRUE</connection-url>
<connection-property name="characterEncoding">utf8</connection-property>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password></password>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>

星期四, 五月 22, 2008

vi的替换命令

关于vi替换命令的使用说明

:s/vivian/sky/ 替换当前行第一个 vivian 为 sky

:s/vivian/sky/g 替换当前行所有 vivian 为 sky

:n,$s/vivian/sky/ 替换第 n 行开始到最后一行中每一行的第一个 vivian 为 sky

:n,$s/vivian/sky/g 替换第 n 行开始到最后一行中每一行所有 vivian 为 sky

n 为数字,若 n 为 .,表示从当前行开始到最后一行

:%s/vivian/sky/(等同于 :g/vivian/s//sky/) 替换每一行的第一个 vivian 为 sky

:%s/vivian/sky/g(等同于 :g/vivian/s//sky/g) 替换每一行中所有 vivian 为 sky

可以使用 # 作为分隔符,此时中间出现的 / 不会作为分隔符

:s#vivian/#sky/# 替换当前行第一个 vivian/ 为 sky/

:%s+/oradata/apras/+/user01/apras1+ (使用+ 来 替换 / ): /oradata/apras/替换成/user01/apras1/

1.:s/vivian/sky/ 替换当前行第一个 vivian 为 sky

:s/vivian/sky/g 替换当前行所有 vivian 为 sky

2. :n,$s/vivian/sky/ 替换第 n 行开始到最后一行中每一行的第一个 vivian 为 sky

:n,$s/vivian/sky/g 替换第 n 行开始到最后一行中每一行所有 vivian 为 sky

(n 为数字,若 n 为 .,表示从当前行开始到最后一行)

3. :%s/vivian/sky/(等同于 :g/vivian/s//sky/) 替换每一行的第一个 vivian 为 sky

:%s/vivian/sky/g(等同于 :g/vivian/s//sky/g) 替换每一行中所有 vivian 为 sky


4. 可以使用 # 作为分隔符,此时中间出现的 / 不会作为分隔符

:s#vivian/#sky/# 替换当前行第一个 vivian/ 为 sky/

5. 删除文本中的^M

问题描述:对于换行,window下用回车换行(0A0D)来表示,linux下是回车(0A)来表示。这样,将window上的文件拷到unix上用时,总会有个^M.请写个用在unix下的过滤windows文件的换行符(0D)的shell或c程序。

· 使用命令:cat filename1 | tr -d “^V^M” > newfile;

· 使用命令:sed -e “s/^V^M//” filename > outputfilename。需要注意的是在1、2两种方法中,^V和^M指的是Ctrl+V和Ctrl+M。你必须要手工进行输入,而不是粘贴。

· 在vi中处理:首先使用vi打开文件,然后按ESC键,接着输入命令:%s/^V^M//。

· :%s/^M$//g

如果上述方法无用,则正确的解决办法是:

· tr -d "\r" <>dest

· tr -d "\015" dest

· strings A>B

6. 其它

利用 :s 命令可以实现字符串的替换。具体的用法包括:

:s/str1/str2/ 用字符串 str2 替换行中首次出现的字符串 str1

:s/str1/str2/g 用字符串 str2 替换行中所有出现的字符串 str1

:.,$ s/str1/str2/g 用字符串 str2 替换正文当前行到末尾所有出现的字符串 str1

:1,$ s/str1/str2/g 用字符串 str2 替换正文中所有出现的字符串 str1

:g/str1/s//str2/g 功能同上

从上述替换命令可以看到:g 放在命令末尾,表示对搜索字符串的每次出现进行替换;不加 g,表示只对搜索

字符串的首次出现进行替换;g 放在命令开头,表示对正文中所有包含搜索字符串的行进行替换操作

JBOSS 4.2.X启动绑定IP,及外部访问问题

一般来说是两个方法。
一个是在JAVA_OPTS后面加入:-Djboss.bind.address=0.0.0.0,
同时并且要在/etc/hosts里加入 其他行除了 127.0.0.0 hostname localhost之外。

IPAddress hostname

另外一种是启动的时候加入-b 0.0.0.0的选择。
run.sh -b 0.0.0.0

这样也可以

星期二, 五月 20, 2008

EJB 的java.lang.ClassCastException错误

Jboss发布EJB成功后,再java 类中后调用出现错误:
一下代码行引起了错误:
PortableRemoteObject.narrow(objref, JControllerHome.class);
objRef是通过lookup找到的JNDI引用。
JControllerHome.class是stateless session bean

错误:

java.lang.ClassCastException: $Proxy59 cannot be cast to org.omg.CORBA.Object
at com.sun.corba.se.impl.javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:212)
at javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:137)

原因,当前Java Class有两个.class文件分别放在不用的目录下,JBOSS 4.2x系列的classloader对class安全载入验证严格,引起了这种问题。

解决方法:删除掉一个不需要的.class的文件,就可以了

星期三, 四月 30, 2008

如何得到JSON对象的数目?

JSON对象不支持length属性。如果想得到一个JSON包含的最顶层的对象的数目,必须用
for 函数来遍历
一种是单纯的数组:

strJSON = "['one','two',{obj1:'obj1_one',obj2:'obj2_two'}]";
var arrObj = eval('(' +strJSON+ ')');
alert(arrObj.length);

另外一种是复杂对象:

var jsonString = "{field1:'data1',field2:'data2',arrField1:['arrField1Content1','arrField1Content2']}";
var obj = eval('(' + jsonString + ')');

var objCount=0;
for(_obj in obj) objCount++;

alert(objCount);

星期一, 二月 11, 2008

RealPlay 11 的不兼容

如果机器安装了Realplay 11版本后,会出现很多视频或音频转换出现无声音的情况。
比如使用kmplayer放电影或 .rmvb无声音的情况.
或者WinAVI Video Converter 7.x,8.0版本转换视频到手机等其他格式的时候,只有图像,
没有声音。

解决的办法是用realplay 10.x的cook.dll来替换realplay 11版本的cook.dll,这样启动机器后,就正常了。这个dll在目录C:\Program Files\Common Files\Real\Codecs下。

这个情况很糟糕,希望以后能改进。

星期六, 一月 19, 2008

如何配置apache,jboss mod_jk一起工作

Apache和Mod_nk配置部分:
http://labs.jboss.com/jbossas/docs/Clustering_Guide/beta422/html/clustering-http-modjk.html

Apache下载:

http://httpd.apache.org/

Mod_Jk下载:
http://tomcat.apache.org/download-connectors.cgi
编译好的版本:
http://apache.mirror.phpchina.com/tomcat/tomcat-connectors/jk/binaries/
注意下载对应的apache http server的正确版本。
mod_jk-1.2.26-httpd-2.2.6.so   这个名字表示对应http server 2.2.6的版本,

其他配置,参看jboss文档

星期五, 一月 18, 2008

Kaspersky 注册表的删除

Windows Registry Editor Version 5.00
[-HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/SystemCertificates/SPC/Certificates]
[-HKEY_LOCAL_MACHINE/SOFTWARE/KasperskyLab/LicStorage]
[-HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Cryptography/RNG]

保存,为k.reg,然后运行就可以删除啦。

星期三, 一月 16, 2008

Redhat 如何打开 telnet

主要是iptable的负作用。
需要如此
/etc/init.d/./ipchains stop
/etc/init.d/./xinetd restart //重起xinetd

如果需要允许root远程登录,修改
/etc/securetty
加入:
pts/0,pts/1