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 &lt;td&gt;の 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 リンクを囲む &lt;td&gt;の 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 ) );
}


/**
* ナビリンクを配置する&lt;td&gt;タグに対するCSSクラス名称を設定します。
*
* @param naviCellClass ナビリンクを配置するセルのCSSクラス名称。
*/
public void setNaviCellClass( String naviCellClass ) {
this.naviCellClass = naviCellClass;
}

/**
* 末端ナビリンクを配置する&lt;td&gt;タグに対するCSSクラス名称を設定します。
*
* @param naviTailCellClass 末端ナビリンクを配置するセルのCSSクラス名称。
*/
public void setNaviTailCellClass( String naviTailCellClass ) {
this.naviTailCellClass = naviTailCellClass;
}

/**
* ナビリンクの&lt;a&gt;タグに対するCSSクラス名称を設定します。
*
* @param naviLinkClass ナビリンクのCSSクラス名称。
*/
public void setNaviLinkClass( String naviLinkClass ) {
this.naviLinkClass = naviLinkClass;
}

/**
* 末端ナビリンクの&lt;a&gt;タグに対する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;
}

/**
* &lt;tr&gt;タグに対するCSSクラス名称を設定します。
* @param rowClass &lt;tr&gt;タグに対するCSSクラス名称。
*/
public void setRowClass( String rowClass ) {
this.rowClass = rowClass;
}


}
最終更新:2011年08月28日 23:14