2011-08-28 23:14:46 (Sun)
package tag;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.ServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.Tag;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.Globals;
import org.apache.struts.taglib.TagUtils;
import org.apache.struts.util.MessageResources;
/**
* パンくずリストタグのハンドラクラス。
*
* @author TAKAO
*/
public class BreadNaviTag extends BodyTagSupport {
/** serialVersionUID。 */
private static final long serialVersionUID = 1L;
/** ログ出力。 */
private static final Log LOGGER = LogFactory.getLog( BreadNaviTag.class );
/** アクション名ならび */
private String actions;
/** ナビリンクを配置する <td>タグに対するCSSクラス名称。 */
private String naviCellClass;
/** 末端ナビリンクを配置する <td>タグに対するCSSクラス名称。 */
private String naviTailCellClass;
/** ナビリンク <a>タグに対するCSSクラス名称。 */
private String naviLinkClass;
/** 末端ナビリンク <a>タグに対するCSSクラス名称。 */
private String naviTailLinkClass;
/**
* 末端をリンクで出力するか否かの設定。
* リンクとする場合、true。
* リンクとしない場合、false。
*/
private boolean tailLinked;
/**
* テーブル全体のborder属性。
*/
private String border;
/**
* テーブル全体のcellpadding属性。
*/
private String cellpadding;
/**
* テーブル全体のcellspacing属性。
*/
private String cellspacing;
/**
* テーブル全体のCSSクラス名称。
*/
private String styleClass;
/**
* <tr>タグに対するCSSクラス名称。
*/
private String rowClass;
/**
* ボディ部評価後の処理。 <br/>
* ボディ部分の文字列をトリム取得して、アクション並びとして保存します。
*
* @return {@link Tag#SKIP_BODY}
* @throws JspException
* ボディ部の文字列を読み取りに失敗したとき。
* @see BodyTagSupport#doAfterBody()
*/
@Override
public int doAfterBody() throws JspException {
BufferedReader reader = null;
StringWriter stringWriter = null;
PrintWriter printWriter = null;
try {
reader = new BufferedReader( this.bodyContent.getReader() );
stringWriter = new StringWriter();
printWriter = new PrintWriter( stringWriter );
while ( true) {
String line = reader.readLine();
if ( line == null ) {
break;
}
printWriter.println( line );
}
printWriter.close();
printWriter = null;
this.actions = stringWriter.toString().trim();
BreadNaviTag.LOGGER.debug( "actions=[" + this.actions + "]" );
}
catch ( IOException e ) {
new JspException( e );
}
finally {
if ( reader != null ) {
try {
reader.close();
}
catch ( IOException e ) {
BreadNaviTag.LOGGER.error( e, e );
}
}
}
return Tag.SKIP_BODY;
}
/**
* 終了タグの評価します。
*
* @return {@link Tag#EVAL_PAGE}
* @throws JspException
* 出力に失敗した場合。
* @see BodyTagSupport#doEndTag()
*/
@Override
public int doEndTag() throws JspException {
try {
this.doEndTagMain();
}
catch ( IOException e ) {
throw new JspException( e );
}
return Tag.EVAL_PAGE;
}
/**
* 終了タグの評価時の処理を実施します。
*
* @throws IOException 出力に失敗した場合。
*/
private void doEndTagMain() throws IOException {
ServletRequest request = this.pageContext.getRequest();
String actions = (String) request.getAttribute(
BreadNaviTag.class.getName() );
if ( !BreadNaviTag.isEmpty( actions ) ) {
this.actions = actions;
}
BreadNaviTag.LOGGER.debug( "actions=[" + this.actions + "]" );
if ( BreadNaviTag.isEmpty( this.actions ) ) {
return;
}
String[] actionNames = this.actions.split( "," );
BreadNaviTag.LOGGER.debug( "actionNames.length=[" + actionNames.length + "]" );
if ( ( actionNames == null ) || ( actionNames.length == 0 ) ) {
return;
}
JspWriter out = this.pageContext.getOut();
// <table>タグ
out.print( "<table" );
if (! BreadNaviTag.isEmpty( this.border )) {
out.print( " border=\"" + this.border + "\"" );
}
if (! BreadNaviTag.isEmpty( this.cellpadding )) {
out.print( " cellpadding=\"" + this.cellpadding + "\"" );
}
if (! BreadNaviTag.isEmpty( this.cellspacing )) {
out.print( " cellspacing=\"" + this.cellspacing + "\"" );
}
if (! BreadNaviTag.isEmpty( this.styleClass )) {
out.print( " class=\"" + this.styleClass + "\"" );
}
out.print( ">" );
out.println();
// <tr>タグ
out.print( "<tr" );
if (! BreadNaviTag.isEmpty( this.rowClass )) {
out.print( " class=\"" + this.rowClass + "\"" );
}
out.print( ">" );
out.println();
int actionNamesLength = actionNames.length;
for ( int index = 0 ; index < actionNamesLength - 1 ; index++ ) {
String actionName = actionNames[ index ];
this.outputLink( actionName, this.naviCellClass, this.naviLinkClass );
}
if ( actionNamesLength > 0 ) {
String actionName = actionNames[ actionNamesLength - 1 ];
String naviCellClass = this.naviTailCellClass;
if ( BreadNaviTag.isEmpty( naviCellClass ) ) {
naviCellClass = this.naviCellClass;
}
String naviLinkClass = this.naviTailLinkClass;
if ( BreadNaviTag.isEmpty( naviLinkClass ) ) {
naviLinkClass = this.naviLinkClass;
}
if (this.tailLinked) {
this.outputLink( actionName, naviCellClass, naviLinkClass );
}
else {
this.outputBreadNaviCell( actionName, naviCellClass, naviLinkClass );
}
}
out.println( "</tr>" );
out.println( "</table>" );
}
/**
* リンクとなっていないセルを出力します。
*
* @param actionName アクション名称。この名称はあくまでリンクの
* @param naviCellClass <td>の CSSクラス。
* @param naviLinkClass 文言に設定するCSSクラス。
* @throws IOException 出力に失敗した場合。
*/
private void outputBreadNaviCell(
String actionName,
String naviCellClass, String naviLinkClass ) throws IOException {
// アクション名称に対応するリンク・タイトルを取得
String title = getBreadNaviTitle( actionName );
JspWriter out = this.pageContext.getOut();
// TDタグ
out.print( "<td" );
// セルのCSSクラス
if ( !BreadNaviTag.isEmpty( naviCellClass ) ) {
out.print( " class=\"" );
out.print( naviCellClass );
out.print( "\"" );
}
out.print( ">" );
// 文言に対するCSSクラス
if ( !BreadNaviTag.isEmpty( naviLinkClass ) ) {
out.print( "<span class=\"" );
out.print( naviLinkClass );
out.print( "\"" );
out.print( ">" );
}
// タイトルの出力
out.print( title );
if ( !BreadNaviTag.isEmpty( naviLinkClass ) ) {
out.print( "</span>" );
}
// 終了タグの出力
out.print( "</td>" );
out.println();
}
/**
* 指定したアクション名称に対応するリンク・セルを出力します。
*
* @param actionName アクション名称。
* @param naviCellClass リンクを囲む <td>の CSSクラス。
* @param naviLinkClass リンクに設定するCSSクラス。
* @throws IOException 出力に失敗した場合。
*/
private void outputLink(
String actionName, String naviCellClass, String naviLinkClass )
throws IOException {
// アクション名称に対応するリンク・タイトルを取得
String title = getBreadNaviTitle( actionName );
// アクション名称に対応するリンクURLを取得
TagUtils tagUtils = TagUtils.getInstance();
String url = tagUtils.getActionMappingURL(
actionName, null, this.pageContext, false );
JspWriter out = this.pageContext.getOut();
// TDタグ
out.print( "<td" );
// セルのCSSクラス
if ( !BreadNaviTag.isEmpty( naviCellClass ) ) {
out.print( " class=\"" );
out.print( naviCellClass );
out.print( "\"" );
}
out.print( ">" );
// リンク
out.print( "<a" );
// リンクのCSSクラス
if ( !BreadNaviTag.isEmpty( naviLinkClass ) ) {
out.print( " class=\"" );
out.print( naviLinkClass );
out.print( "\"" );
}
// リンク先の設定
out.print( " href=\"" );
out.print( url );
out.print( "\"" );
out.print( ">" );
// タイトルの出力
out.print( title );
// 終了タグの出力
out.print( "</a>" );
out.print( "</td>" );
out.println();
}
/**
* 指定したアクション名称に対応するパンくずタイトル(リンク文言)を取得します。
* @param actionName アクション名称。
* @return パンくずタイトル。
* @see MessageResources
*/
private String getBreadNaviTitle( String actionName ) {
// Strutsが使用するメッセージ・リソース。
MessageResources mr = (MessageResources) this.pageContext
.getServletContext().getAttribute( Globals.MESSAGES_KEY );
// リンクに表示する文字列を取得します。
String title = mr.getMessage( "breadnavi." + actionName );
return title;
}
/**
* 指定した文字列が空文字列であるか判定します。
*
* @param str 判定対象の文字列。
* @return 引数の文字列が null または 長さ0の場合、true。その他はfalse。
*/
private static boolean isEmpty( String str ) {
return ( ( str == null ) || ( str.length() == 0 ) );
}
/**
* ナビリンクを配置する<td>タグに対するCSSクラス名称を設定します。
*
* @param naviCellClass ナビリンクを配置するセルのCSSクラス名称。
*/
public void setNaviCellClass( String naviCellClass ) {
this.naviCellClass = naviCellClass;
}
/**
* 末端ナビリンクを配置する<td>タグに対するCSSクラス名称を設定します。
*
* @param naviTailCellClass 末端ナビリンクを配置するセルのCSSクラス名称。
*/
public void setNaviTailCellClass( String naviTailCellClass ) {
this.naviTailCellClass = naviTailCellClass;
}
/**
* ナビリンクの<a>タグに対するCSSクラス名称を設定します。
*
* @param naviLinkClass ナビリンクのCSSクラス名称。
*/
public void setNaviLinkClass( String naviLinkClass ) {
this.naviLinkClass = naviLinkClass;
}
/**
* 末端ナビリンクの<a>タグに対するCSSクラス名称を設定します。
*
* @param naviLinkCellClass 末端ナビリンクのCSSクラス名称。
*/
public void setNaviTailLinkClass( String naviLinkCellClass ) {
this.naviTailLinkClass = naviLinkCellClass;
}
/**
* 末端をリンクで出力するか否かの設定します。
* @param tailLinked リンクとする場合、true。リンクとしない場合、false。
*/
public void setTailLinked( Object tailLinked ) {
// null であればリンクにしない
if (tailLinked == null) {
this.tailLinked = false;
return;
}
// Booleanであれば、値を取得
if (Boolean.class.isInstance( tailLinked) ){
this.tailLinked = ((Boolean)tailLinked).booleanValue();
return;
}
// String であれば、parseする
if (String.class.isInstance( tailLinked )) {
this.tailLinked = Boolean.parseBoolean( (String)tailLinked );
return;
}
// その他は例外
throw new IllegalArgumentException(
"the attribute \"tailLinked\" cannot be parsed boolean."
+ " value=[" + tailLinked +"] class=[" + tailLinked.getClass() + "]");
}
/**
* テーブル全体のborder属性を設定します。
* @param border テーブル全体のborder属性。
*/
public void setBorder( String border ) {
this.border = border;
}
/**
* テーブル全体のcellpadding属性を設定します。
* @param cellpadding テーブル全体のcellpadding属性。
*/
public void setCellpadding( String cellpadding ) {
this.cellpadding = cellpadding;
}
/**
* テーブル全体のcellspacing属性を設定します。
* @param cellspacing テーブル全体のcellspacing属性。
*/
public void setCellspacing( String cellspacing ) {
this.cellspacing = cellspacing;
}
/**
* テーブル全体のCSSクラス名称を設定します。
* @param styleClass テーブル全体のCSSクラス名称。
*/
public void setStyleClass( String styleClass ) {
this.styleClass = styleClass;
}
/**
* <tr>タグに対するCSSクラス名称を設定します。
* @param rowClass <tr>タグに対するCSSクラス名称。
*/
public void setRowClass( String rowClass ) {
this.rowClass = rowClass;
}
}
最終更新:2011年08月28日 23:14