2009年4月30日星期四

Wicket+Guice+Warp-Persist+Hibernate配置

Wicket1.4中已经有独立的Guice模块,但Guice只是一个IoC框架,不支持对事务等的管理;Warp-Persist是Guice下的一个支持事务管理的框架,它支持多种ORM框架,如:Hibernate、Jpa等。当前,配置Wicket+Guice+Warp-Persist+Hibernate已经非常简单,几个步骤即可:

1. download相应框架的jar包和运行时必须的lib;Guice当前的版本已经升级到2.0 snapshot,只需要guice-core.jar和aopalliance.jar,warp-persist也只需求找一个最新的jar包即可;Wicket和Hibernate所需的lib比较多,主要需要注意cglib和slf4j(日志)。

2. 创建一个Guice的Module,扩展AbstractModule即可。

3. Module中首先装载Warp-Persist:
install(PersistenceService.usingHibernate().across(UnitOfWork.REQUEST).buildModule());

4. 然后配置hibernate configuation,我这里用的是AnnotationConfiguration,切记:configuration中一定要指定current_session_context_class这个参数。hibernate.cfg.xml放在WEB-INF/classes目录下。
AnnotationConfiguration result = new AnnotationConfiguration();
result.configure(ServiceModule.class.getResource("/hibernate.cfg.xml"));
result .setProperty("hibernate.current_session_context_class", "managed");
bind(Configuration.class).toInstance(result);


5. 最后,配置web.xml,一定要注意Warp‘s Filter和WicketFilter的位置,Warp‘s Filter一定要放置在WicketFilter的前面。并且指定WicketFilter的applicationFactoryClassName和module参数。
<filter>
<filter-name>sessionPerRequestFilter<filter-name>
<filter-class>com.wideplay.warp.persist.PersistenceFilter<filter-class>
</filter>
<filter-mapping>
<filter-name>sessionPerRequestFilter<filter-name>
<url-pattern>/*<url-pattern>
</filter-mapping>

<filter>
<filter-name>wicketFilter<filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter<filter-class>

<init-param>
<param-name>applicationFactoryClassName<param-name>
<param-value>org.apache.wicket.guice.GuiceWebApplicationFactory<param-value>
</init-param>
<init-param>
<param-name>module<param-name>
<param-value>com.deversoft.test.guice.WicketModule<param-value>
</init-param>
<init-param>
<param-name>wicket-guice.stage<param-name&gt
<param-value>DEVELOPMENT<param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>wicketFilter<filter-name>
<url-pattern>/*<url-pattern>
</filter-mapping>



参考资料:
  1. Bleeding Edge Transactional Wicket Web Applications with Warp and Guice
  2. Warp
  3. Wicket
  4. Google-Guice

2009年4月29日星期三

Wicket1.4中调用外部资源的方法

在wicket中,要使用js或css文件,需要将这些文件包装成ResourceReference,通过ResourceReference就可以将js或css文件加入到wicket页面对象中。因此,我分别创建了2个Enum对象:DefaultJavascript和DefaultStyle,如下:
public enum DefaultStyle {
Header("header.css"), MainPage("main-page.css");
private String cssName;
DefaultStyle(String cssName) {
this.cssName = cssName;
}

public ResourceReference getResouceReference() {
return new ResourceReference(DefaultStyle.class, cssName);
}
}
通过DefaultStyle来将css文件封装成ResourceReference对象,js文件要照此处理,比较方便。

要将ResourceReference加入到wicket中,在wicket1.4版本中,
加css文件:
add(CSSPackageResource.getHeaderContribution(DefaultStyle.Popup
.getResouceReference()));
加js文件:
add(JavascriptPackageResource.getHeaderContribution(DefaultJavascript.JQuery
.getResouceReference()));
稍微麻烦一点的是对图片的处理,一般存在三种方式:
  1. 如果在页面中使用了Img标签,那可以按上面js或css方式来进行处理,通过ResourceReference对象来包装。
  2. 如果是在css文件中直接使用图片,可以根据css文件与图片文件所在的相对路径来直接设置。譬如:jquery.tab.css文件放在com.deversoft.web.tab包下,tab-bottom.gif图片放在com.deversoft.web.tab.images包下。那在css文件中可以直接通过images/tab-bottom.gif来进行使用。
  3. 如果是在js文件中直接使用图片,需要引用图片ResouceReference对象的路径。譬如,还是上面的图片tab-bottom.gif,在js中调用,就需要这样调用:resources/com.deversoft.web.tab.DefaultImage/tab-bottom.gif。这其实和第一种方式以相同的。

2009年4月20日星期一

可关闭的Wicket TabbedPanel

Wicket中自带的TabbedPanel是不能关闭的,而在项目中,却要使用可以关闭的Tabs,因此参考Wicket Wiki上的例子,自己实现了一套带关闭图标的TabbedPannel。具体实现方式如下:
第一步:创建一个abstract SimpleAbstractTab类,扩展AbstractTab。
public abstract class SimpleAbstractTab extends AbstractTab {
private String title;
private boolean canBeClosed;

public SimpleAbstractTab(IModel iModel, String title, boolean canBeClosed) {
super(iModel);
this.title = title;
this.canBeClosed = canBeClosed;
}

public String getOngletTitle() {
return this.title;
}

public boolean isCanBeClosed() {
return canBeClosed;
}
}

第二步:创建一个SimpleTabbedPanel,扩展TabbedPanel。

public class SimpleTabbedPanel extends Panel {
private static final long serialVersionUID = 1L;
public static final String TAB_PANEL_ID = "panel";

private String whereAmI;
private final List tabs;

public SimpleTabbedPanel(String id, List tabs) {
super(id, new Model(new Integer(-1)));
add(CSSPackageResource.getHeaderContribution(DefaultStyle.TabbedPanel.getResouceReference()));
this.setOutputMarkupId(true);

if (tabs == null) {
throw new IllegalArgumentException("argument [tabs] cannot be null");
}

this.tabs = tabs;

final IModel tabCount = new AbstractReadOnlyModel() {
private static final long serialVersionUID = 1L;

public Object getObject() {
return new Integer(SimpleTabbedPanel.this.tabs.size());
}
};

WebMarkupContainer tabsContainer = new WebMarkupContainer(
"tabs-container") {
private static final long serialVersionUID = 1L;

protected void onComponentTag(ComponentTag tag) {
super.onComponentTag(tag);
tag.put("class", getTabContainerCssClass());
}
};
add(tabsContainer);

// add the loop used to generate tab names
tabsContainer.add(new Loop("tabs", tabCount) {
private static final long serialVersionUID = 1L;

protected void populateItem(LoopItem item) {
final int index = item.getIteration();

final WebMarkupContainer titleLink = newLink("link", index);

titleLink.add(newTitle("title", SimpleTabbedPanel.this.tabs
.get(index).getOngletTitle(), index));
item.add(titleLink);

final AjaxLink closeLink = newAjaxLink("closeTab", index);
closeLink.add(new Image("closeImg", DefaultImage.TabClosed.getResouceReference()));
if (!SimpleTabbedPanel.this.tabs.get(index).isCanBeClosed())
closeLink.setVisible(false);
item.add(closeLink);
}

protected LoopItem newItem(int iteration) {
return newTabContainer(iteration);
}

});

this.whereAmI = this.tabs.get(0).getOngletTitle();
}

protected LoopItem newTabContainer(int tabIndex) {
return new LoopItem(tabIndex) {
private static final long serialVersionUID = 1L;

protected void onComponentTag(ComponentTag tag) {
super.onComponentTag(tag);
String cssClass = (String) tag.getString("class");
if (cssClass == null) {
cssClass = " ";
}
cssClass += " tab" + getIteration();

if (getIteration() == getSelectedTab()) {
cssClass += " selected";
}
if (getIteration() == getTabs().size() - 1) {
cssClass += " last";
}
tag.put("class", cssClass.trim());
}

};
}

protected void onBeforeRender() {
super.onBeforeRender();
if (!hasBeenRendered() && getSelectedTab() == -1) {
// select the first tab by default
setSelectedTab(0);
}
}

protected String getTabContainerCssClass() {
return "tab-row";
}

public final List getTabs() {
return tabs;
}

protected Component newTitle(String titleId, String title, int index) {
return new Label(titleId, title);
}

public void newTab(AjaxRequestTarget target, SimpleAbstractTab tab) {
this.tabs.add(tab);
this.setSelectedTab(this.tabs.size()-1);
target.addComponent(this);
}

public void removeTab(AjaxRequestTarget target, int index) {
String titleDeletedTab = this.tabs.get(index).getOngletTitle();
this.tabs.remove(index);

if (titleDeletedTab.equals(this.whereAmI)) {
this.setSelectedTab(0);
this.whereAmI = this.tabs.get(0).getOngletTitle();
} else {
this.setSelectedTab(this.findSelectedTab(whereAmI));
}

target.addComponent(this);
}

protected int findSelectedTab(String title) {
int result = 0;
for (int i = 0; i < result =" i;">= tabs.size()) {
throw new IndexOutOfBoundsException();
}

setDefaultModelObject(new Integer(index));

ITab tab = (ITab) tabs.get(index);

Panel panel = tab.getPanel(TAB_PANEL_ID);

if (panel == null) {
throw new WicketRuntimeException(
"ITab.getPanel() returned null. TabbedPanel [" + getPath()
+ "] ITab index [" + index + "]");

}

if (!panel.getId().equals(TAB_PANEL_ID)) {
throw new WicketRuntimeException(
"ITab.getPanel() returned a panel with invalid id ["
+ panel.getId()
+ "]. You must always return a panel with id equal to the provided panelId parameter. TabbedPanel ["
+ getPath() + "] ITab index [" + index + "]");
}

if (get(TAB_PANEL_ID) == null) {
add(panel);
} else {
replace(panel);
}

this.whereAmI = this.tabs.get(index).getOngletTitle();
}

public final int getSelectedTab() {
return ((Integer) getDefaultModelObject()).intValue();
}
}


第三步:同时,创建一个SimpleTabbedPanel.html,页面如下:

[wicket:panel]
[div wicket:id="tabs-container" class="tab-row"]
[ul]
[li wicket:id="tabs"]
[div class="tab"]
[a href="#" wicket:id="link" class="tab-link"][span wicket:id="title"]tab title[/span][/a]
[a href="#" wicket:id="closeTab" class="tab-close"][img wicket:id="closeImg" alt="Close" border=0/][/a]
[/div]
[/li]
[/ul]
[/div]
[div wicket:id="panel" class="tab-panel"]panel[/div]
[/wicket:panel]

第四步:创建一个css文件,并使用一个close的icon。
div.tabpanel div.tab-row ul {
height: 20px;
margin: 0;
padding-left: 10px;
background: url( images/tab_bottom.gif ) repeat-x bottom;
}

div.tabpanel div.tab-row li {
margin: 0;
padding:0 5px 0 0;
display: inline;
list-style-type: none;
}

div.tabpanel div.tab-row div.tab {
float:left;
display:block;
background:#f3f3f3;
padding:5px 7px 4px 20px;
text-decoration:none;
font-weight:bold;
color:#9cf;
border: 1px solid #ccc;
white-space:nowrap;
}

div.tabpanel div.tab-row a.tab-link:link, div.tabpanel div.tab-row a.tab-link:visited {
float: left;
background: #f3f3f3;
font-size: 12px;
line-height: 14px;
font-weight: bold;
padding:5px 10px 4px 10px;
margin-right: 4px;
text-decoration: none;
color: #666;
}

div.tabpanel div.tab-row li.selected a.tab-link:link, div.tabpanel div.tab-row a.tab-link:visited.active {
border-bottom: 1px solid #fff;
background: #fff;
color: #000;
}

div.tabpanel div.tab-row a.tab-link:hover {
background: #fff;
}

div.tabpanel div.tab-row a.tab-close:hover {
background: #B9D4E8;
}

第五步:实现几个panel,如FirstTab等都是自己任意实现的Panel,调用SimpleTabbedPanel

//tabs
final List tabs = new ArrayList();
tabs.add(new SimpleAbstractTab(new Model("first tab"), "simple tab1", true) {
@Override
public Panel getPanel(final String panelId) {
return new FirstTab(panelId);
}
});
final SimpleTabbedPanel tabbedPanel = new SimpleTabbedPanel("tabs", tabs);
add(tabbedPanel);

// The AjaxLink to new tab
add(new AjaxLink("newTab"){
public void onClick(AjaxRequestTarget target) {
tabbedPanel.newTab(target, new SimpleAbstractTab(new Model("first tab"), "new Tab", true) {
@Override
public Panel getPanel(final String panelId) {
return new NewTab(panelId);
}
});
}
});



2009年4月9日星期四

Install Mysql-Proxy 0.7.0 on openSUSE 11.1

steps:
  1. install pkg-config (yast2)
  2. install autotools && libtool && libmysql-devel (yast2)
  3. install libevent(> 1.4.0) && libevent-devel (yast2)
  4. install glib2(>2.0) && glib2-devel (yast2)
  5. install Lua 5.1 && Lua-devel (yast2)
  6. export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/pkgconfig
  7. download mysql-proxy 0.7.0 sources code
  8. ./autogen.sh && ./configuration && make && install
  9. export PATH=$PATH:/usr/local/sbin
  10. mysql-proxy -V


2009年4月7日星期二

VMware Server2.0: install vmware tools

摆弄了VMware server 2.0一段时间,终于找到怎样来安装vmware tool了。当安装完虚机后,可以将虚机add virtual machine to Inventory。这样左边Inventory目录中就会显示该虚机名称。

先启动该虚机,当打开该虚机的summary tab页时,在右边显示的status信息栏中会出现vmware tools的状态,如果已经安装了,就会显示出running;如果没有安装,则会显示【install vmware tool】的链接。点击该链接,虚机中会自动加载vmware tools的cdrom。通过cdrom就可以安装vmware tools了。


2009年4月3日星期五

mysql5主从备份

这两天在虚机(linux)上搭建了mysql5(imysam)的主从备份机制,廖作记录:

Master
  1. new db :2x_db,and new table: test, input some data;
  2. mysqldump 2x_db to 2x_db_dump.sql,then transfer to slave machine;
  3. modify my.cnf:
log-bin = /var/lib/mysql/master.log
log-bin-index = /var/lib/mysql/master.index.log
binlog-do-db = 2x_db
server-id = 1
   4. start mysql,and create replicate user:
GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%' IDENTIFIED BY 'replicator';

5. flush privileges;
6.show master status,then record this info

Slave:
1. modify my.cnf:
server-id=2
master-host=master machine's ip
master-user=replicator
master-password=replicator
master-log-file=master.000002 // from show master status: logfile
master-log-pos=98 // from show master status: logPos
master-connect-retry=60
replicate-do-db=2x_db

2. start mysql,then new db: 2x_db
3. load 2x_db.sql into 2x_db
4. login in mysql,show slave status

Test:
1. login in master's mysql,insert one record;
2. then login in slave's mysql,select this table;