org.mixer2.xhtml.AbstractJaxb Maven / Gradle / Ivy
package org.mixer2.xhtml;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import java.util.regex.Pattern;
import javax.xml.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mixer2.jaxb.xhtml.Footer;
import org.mixer2.jaxb.xhtml.Header;
import org.mixer2.jaxb.xhtml.Input;
import org.mixer2.util.CastUtil;
import org.mixer2.util.M2StringUtils;
import org.mixer2.xhtml.exception.TagTypeUnmatchException;
import org.mixer2.xhtml.util.*;
/**
*
* base class of all tag type
*
*
* @author nabedge
*
*/
@javax.xml.bind.annotation.XmlTransient
public abstract class AbstractJaxb implements Serializable {
private static Log log = LogFactory.getLog(AbstractJaxb.class);
private static final long serialVersionUID = 1L;
/**
*
* type cast.
*
*
*
* // usage:
* // get a TD tag of first row, first column.
* Td td = html.getById("foo", Table.class).getTr().get(0).getThOrTd().get(0)
* .cast(Td.class);
*
*
* @param clazz
* tag type of org.mixer2.jaxb.xhtml.*
* @return
*/
public T cast(Class clazz) {
return CastUtil. cast(this);
}
/**
*
* get tag that has specified id attribute. You don't need to cast() because
* you can specify the tag type.
*
*
*
* // sample: get a Div tag having id="foo" attribute.
* html.getById("foo", Div.class);
*
*
* @param id
* @param tagType
* @return
* @throws TagTypeUnmatchException
*/
@SuppressWarnings("unchecked")
public T getById(String id, Class tagType)
throws TagTypeUnmatchException {
Object obj = GetByIdUtil.getById(id, this);
if (obj != null && !obj.getClass().isAssignableFrom(tagType)) {
throw new TagTypeUnmatchException(tagType.getClass(),
obj.getClass());
}
return (T) obj;
}
/**
*
* get tag that has specified id attribute. To use return value as ussual
* tag, you must cast() it.
*
*
* @param id
* @return
*/
@SuppressWarnings("unchecked")
public T getById(String id) {
Object obj = GetByIdUtil.getById(id, this);
return (T) obj;
}
/**
*
* delete element that has specified attribute within descendant element
* of oneself. you can't delete oneself.
*
*
* @param target
* @return if success to delete, return true. if no hit, return false.
*/
public boolean remove(T target) {
String id = target.getId();
if (id == null) {
for (int i = 0; i < 256; i++) {
id = UUID.randomUUID().toString();
if (this.getById(id) == null) {
target.setId(id);
break;
}
}
}
return RemoveByIdUtil.removeById(id, this);
}
/**
* remove inner content of this tag.
*/
public void removeInner() {
RemoveInnerUtil.removeInner(this);
}
/**
*
* delete element that has specified id attribute within descendant element
* of oneself. you can't delete oneself.
*
*
* @param id
* @return
*/
public boolean removeById(String id) {
return RemoveByIdUtil.removeById(id, this);
}
/**
*
* replace element that has specified attribute within descendant element of
* oneself. you can't replace oneself. It will be replaced by deep copy of
* "replacement"
*
*
* @param target
* @param replacement
* @return if success to replace, return true. if no hit, return false.
* @throws TagTypeUnmatchException
*/
public boolean replace(T target, T replacement)
throws TagTypeUnmatchException {
String id = target.getId();
if (id == null) {
for (int i = 0; i < 256; i++) {
id = UUID.randomUUID().toString();
if (this.getById(id) == null && replacement.getById(id) == null) {
target.setId(id);
break;
}
}
}
return ReplaceByIdUtil.replaceById(id, this, replacement);
}
/**
*
* replace element that has specified id attribute within descendant element
* of oneself. you can't replace oneself. It will be replaced by deep copy
* of "replacement"
*
*
* @param id
* @param replacement
* @return if success to replace, return true. if no hit, return false.
* @throws TagTypeUnmatchException
*/
public boolean replaceById(String id, T replacement)
throws TagTypeUnmatchException {
return ReplaceByIdUtil.replaceById(id, this, replacement);
}
/**
*
* replace element by string. you can't replace oneself.
*
*
* @param id
* @param replacement
* @return if success to replace, return true. if no hit, return false.
* @throws TagTypeUnmatchException
*/
public boolean replaceById(String id,
String replacement) throws TagTypeUnmatchException {
return ReplaceByIdUtil.replaceById(id, this, replacement);
}
/**
*
* scan descendant element that is specified tag type having specified class
* attribute and return it as List.
*
*
*
* // usage:
* // get all div objects having "foo" class
* List<Div> divList = html.getDescendants("foo", Div.class);
* // get all Table objects having "bar" class within <div id="foo">
* List<Table> tbList = html.getById("foo", Div.class).getDescendants("bar",
* Table.class);
*
*
* @param clazz
* @param tagType
* @return
*/
@SuppressWarnings("unchecked")
public List getDescendants(String clazz,
Class tagType) {
return GetDescendantsUtil.getDescendants((T) this, new ArrayList(),
clazz, tagType);
}
/**
*
* scan descendant elements that has specified tag type and return it as
* List.
*
*
*
* // usage:
* // get all div objects.
* html.getDescendants(Div.class);
* // get all table objects within <div id="foo">
* html.getById("foo", Div.class).getDescendants(Table.class);
*
*
* @param tagType
* @return
*/
@SuppressWarnings("unchecked")
public List getDescendants(Class tagType) {
return GetDescendantsUtil.getDescendants((T) this, new ArrayList(),
tagType);
}
/**
*
* scan descendant elements that has specified class attribute and return it
* as List
*
*
* @param clazz
* class attribute
* @return
*/
@SuppressWarnings("unchecked")
public List getDescendants(String clazz) {
return GetDescendantsUtil.getDescendants((T) this, new ArrayList(),
clazz);
}
/**
*
* delete all descendant elements that is specified tag type having
* specified class attribute.
*
*
* @param clazz
* class attribute
* @param tagType
*/
@SuppressWarnings("unchecked")
public void removeDescendants(String clazz,
Class tagType) {
RemoveDescendantsUtil.removeDescendants((T) this, clazz, tagType);
}
/**
*
* delete all descendant elements that is specified tag type.
*
*
* @param tagType
*/
@SuppressWarnings("unchecked")
public void removeDescendants(Class tagType) {
RemoveDescendantsUtil.removeDescendants((T) this, tagType);
}
/**
*
* delete all descendant elements having specified class attribute
*
*
* @param clazz
* class attribute
*/
@SuppressWarnings("unchecked")
public void removeDescendants(String clazz) {
RemoveDescendantsUtil.removeDescendants((T) this, clazz);
}
/**
*
* replace all the descendant elements that is specified tag type having
* specified class attribute. this method use deep copy of "replacement"
*
*
* @param clazz
* class attribute
* @param tagType
* @param replacement
* @throws TagTypeUnmatchException
*/
@SuppressWarnings("unchecked")
public void replaceDescendants(String clazz,
Class tagType, T replacement) throws TagTypeUnmatchException {
ReplaceDescendantsUtil.replaceDescendants((T) this, tagType, clazz,
replacement);
}
/**
*
* replace all the descendant elements by String. The target is specified
* tag type having specified class attribute.
*
*
* @param clazz
* class attribute
* @param tagType
* @param replacement
* @throws TagTypeUnmatchException
*/
@SuppressWarnings("unchecked")
public void replaceDescendants(String clazz,
Class tagType, String replacement)
throws TagTypeUnmatchException {
ReplaceDescendantsUtil.replaceDescendants((T) this, tagType, clazz,
replacement);
}
/**
*
* replace all descendant elements that is specified tag type. This method
* use deep copy of "replacement"
*
*
* @param tagType
* @param replacement
* @throws TagTypeUnmatchException
*/
@SuppressWarnings("unchecked")
public void replaceDescendants(Class tagType,
T replacement) throws TagTypeUnmatchException {
ReplaceDescendantsUtil.replaceDescendants((T) this, tagType,
replacement);
}
/**
* replace all descendant elements that has specified class attribute.
* This method user deep copy of "replacement"
*
* @param clazz class attribute
* @param replacement
* @throws TagTypeUnmatchException
*/
@SuppressWarnings("unchecked")
public void replaceDescendants(String clazz,
T replacement) throws TagTypeUnmatchException {
ReplaceDescendantsUtil.replaceDescendants((T) this, clazz, replacement);
}
/**
*
* replace all descendant element that is specified tag type by String
*
*
* 指定したタグ型の子孫要素を文字列で置換します。
*
*
* @param tagType
* @param replacement
* @throws TagTypeUnmatchException
*/
@SuppressWarnings("unchecked")
public void replaceDescendants(Class tagType,
String replacement) throws TagTypeUnmatchException {
ReplaceDescendantsUtil.replaceDescendants((T) this, tagType,
replacement);
}
/**
*
* replace descendant tag with string. specifying class property.
*
*
* @param clazz
* class attribute
* @param replacement
* @throws TagTypeUnmatchException
*/
@SuppressWarnings("unchecked")
public void replaceDescendants(String clazz,
String replacement) throws TagTypeUnmatchException {
ReplaceDescendantsUtil.replaceDescendants((T) this, clazz, replacement);
}
/**
*
* Replace whole of inside the tag by replacement.
* For various reasons, this method does NOT use deep copy of replacement.
* It is recommended to use copy(T) in method argument.
*
*
* recommended pattern.
*
* // div and p is instance of Div, p tag object.
* Div div = TagCreator.div();
* P p = TagCreator.p();
* p.getContent().add("foo");
* div.replaceInner(p.copy(P.class)); // *** using copy()
* p.getContent().add("bar");
* System.out.println(mixer2Engine.saveToString(div));
* // you get <div><p>foo</p></div>
*
*
* anti pattern. use with caution.
*
* // divA and divB is instance of Div tag object.
* Div div = TagCreator.div();
* P p = TagCreator.p();
* p.getContent().add("foo");
* div.replaceInner(p); // *** without copy()
* p.getContent().add("bar");
* System.out.println(mixer2Engine.saveToString(div));
* // you get <div><p>foo bar</p></div>
*
*
* @param replacement
*/
public void replaceInner(T replacement) {
ReplaceInnerUtil.replaceInner(this, replacement);
}
/**
*
* Replace whole of inside the tag by replacement.
* If this tag can not have String directory (ex. <table> tag), do nothing.
*
*
* @param replacement
*/
public void replaceInner(String replacement) {
ReplaceInnerUtil.replaceInner(this, replacement);
}
/**
*
* Replace whole of inside the tag by the whole elements of the list.
* If the element can not be use in this tag, There is a case that will be exclude.
*
*
* @param replacement
*/
public void replaceInner(List extends java.lang.Object> replacement) {
ReplaceInnerUtil.replaceInner(this, replacement);
}
/**
*
* insert element after the element having specified id attribute. This
* method use deep copy of "insObject"
*
*
* @param id
* id attribute
* @param insObject
* @return true if success to insert. if no hit, return false.
* @throws TagTypeUnmatchException
*/
public boolean insertAfterId(String id, T insObject)
throws TagTypeUnmatchException {
return InsertByIdUtil.insertAfterId(id, insObject, this);
}
/**
* insert String after the element having specified id attribute
*
* @param id
* @param insString
* @return true if success to insert. if no hit, return false.
* @throws TagTypeUnmatchException
*/
public boolean insertAfterId(String id, String insString)
throws TagTypeUnmatchException {
return InsertByIdUtil.insertAfterId(id, insString, this);
}
/**
* insert element before the element having specified id attribute.
* This method use deep copy of insObject
*
*
* @param id
* @param insObject
* @return true if success to insert. if no hit, return false.
* @throws TagTypeUnmatchException
*/
public boolean insertBeforeId(String id,
T insObject) throws TagTypeUnmatchException {
return InsertByIdUtil.insertBeforeId(id, insObject, this);
}
/**
* insert string before the element having specified id attribute.
*
* @param id
* @param insString
* @return true if success to insert. if no hit, return false.
* @throws TagTypeUnmatchException
*/
public boolean insertBeforeId(String id, String insString)
throws TagTypeUnmatchException {
return InsertByIdUtil.insertBeforeId(id, insString, this);
}
/**
*
* write style attribute by TreeMap
*
*
*
* // usage:
* TreeMap<String, String> styleMap = new TreeMap<String, String>();
* styleMap.put("border-color", "red");
* html.getById(Div.class, "hellomsg").setStyleByTreeMap(styleMap);
* // output:
* // <div id="hellomsg" style="border-color:red;">...</div>
*
*
* @param styleMap
*/
public void setStyleByTreeMap(
TreeMap styleMap) {
String str = "";
for (String key : styleMap.keySet()) {
str += key + ":" + styleMap.get(key) + "; ";
}
this.setStyle(str);
}
/**
*
* return style attributes as TreeMap
*
*
* @return
*/
public TreeMap getStyleAsTreeMap() {
TreeMap resultMap = new TreeMap();
if (M2StringUtils.isBlank(this.getStyle())) {
return resultMap;
}
String st[] = this.getStyle().trim().split(";");
String st2[];
for (String s : st) {
st2 = s.split(":");
resultMap.put(st2[0].trim(), st2[1].trim());
}
return resultMap;
}
/**
*
* return deep copy of myself
*
*
* NOTICE: DO NOT USE clone() and copyTo() method !
* They has bug. Use this copy() method instead of them.
*
*
*
* // usage
* Div div = html.getById(Div.class, "foo");
* Div div2 = div.copy(Div.class);
*
*
* @param tagType
* @return
* @throws TagTypeUnmatchException
*/
@SuppressWarnings("unchecked")
public T copy(Class tagType)
throws TagTypeUnmatchException {
T copy = null;
if (!tagType.equals(this.getClass())) {
log.warn("to use copy() method, tagType must be same type of the original object.");
throw new TagTypeUnmatchException(getClass(), tagType);
}
try {
copy = (T) this.clone();
} catch (CloneNotSupportedException e) {
log.error("can not create clone(copy) of this object.", e);
}
CopyUtil.copyOtherAttr(this, copy);
return copy;
}
/**
*
* same as {@link #copy(Class)} but never throw exception.
* return null if failed to copy.
*
*
* @param tagType
* @return
*/
public T copyNoException(Class tagType) {
T copy = null;
try {
copy = (T) this.copy(tagType);
} catch (final TagTypeUnmatchException e) {
return null;
}
return copy;
}
/**
*
* set data-* attribute
*
*
*
* Div div = new Div();
* div.setData("foo", "bar");
* // you get <div data-foo="bar"></div>
*
*
* @param key
* data-"key"
*/
public void setData(String key, String value) {
QName qn = new QName("data-" + key);
this.getOtherAttributes().put(qn, value);
}
/**
*
* return the value of data-* attribute. If not set, return null.
*
*
* @param key
* data-"key"
* @return null if not found attribute
*/
public String getData(String key) {
QName qn = new QName("data-" + key);
return this.getOtherAttributes().get(qn);
}
/**
*
* set area-* attribute
*
*
* @param key
* aria-"key"
* @param value
*/
public void setAria(String key, String value) {
QName qn = new QName("aria-" + key);
this.getOtherAttributes().put(qn, value);
}
/**
*
* return the value of area-* attribute. If not set, return null.
*
*
* @param key
* aria-"key"
* @return
*/
public String getAria(String key) {
QName qn = new QName("aria-" + key);
return this.getOtherAttributes().get(qn);
}
/**
* remove a specified data-* attribute.
*
* @param key data-"key"
* @return the previous value associated with key, or null if there was no mapping for key.
*/
public String removeData(String key) {
QName qn = new QName("data-" + key);
return this.getOtherAttributes().remove(qn);
}
/**
* remove a specified aria-* attribute.
*
* @param key data-"key"
* @return the previous value associated with key, or null if there was no mapping for key.
*/
public String removeAria(String key) {
QName qn = new QName("aria-" + key);
return this.getOtherAttributes().remove(qn);
}
/**
*
* get other attribute map. NOTICE: this method is dummy for make coding
* easy. Acrually, this method is overridden by each tag class.
*
*
* @return
*/
public Map getOtherAttributes() {
return null;
}
/**
*
* get id attribute. return null if not set. NOTICE: this method is dummy for
* make coding easy. Acrually, this method is overridden by each tag class.
*
*
* @return
*/
public String getId() {
return null;
}
/**
*
* set id attribute. NOTICE: this method is dummy for make coding easy.
* Acrually, this method is overridden by each tag class.
*
*/
public void setId(String id) {
}
/**
*
* NOTICE: this method is dummy for make coding easy. Acrually, this method
* is overridden by each tag class.
*
*/
public boolean isSetId() {
return false;
}
/**
*
* remove id attribute of all descendant elements. Also, remove id attribute
* of myself.
*
*/
public void unsetAllId() {
UnsetIdUtil.unsetAllId(this);
}
/**
* remove id attribute that matches specified regex. Also, matches and remove of myself.
*/
public void unsetAllId(Pattern pattern) {
UnsetIdUtil.unsetAllId(this, pattern);
}
/**
*
* NOTICE: this method is dummy for make coding easy. Acrually, this method
* is overridden by each tag class.
*
*
* @return
*/
public String getStyle() {
return null;
}
/**
*
* NOTICE: this method is dummy for make coding easy. Acrually, this method
* is overridden by each tag class.
*
*
* @param value
*/
public void setStyle(String value) {
return;
}
/**
*
* return class attribute as List. NOTICE: this method is dummy for make
* coding easy. Acrually, this method is overridden by each tag class.
*
*
* @return
*/
public List getCssClass() {
return null;
}
/**
*
* return true if have specified class attribute.
*
*
* @param clazz
* class attribute
* @return
*/
public boolean hasCssClass(String clazz) {
boolean result = false;
List classList = this.getCssClass();
if (classList != null && classList.contains(clazz)) {
result = true;
}
return result;
}
/**
*
* add class attribute. If already set, do nothing.
*
*/
public void addCssClass(String clazz) {
List classList = this.getCssClass();
if (!this.hasCssClass(clazz)) {
classList.add(clazz);
}
}
/**
*
* remove specified class attribute if having it.
*
*/
public void removeCssClass(String clazz) {
List classList = this.getCssClass();
if (classList != null) {
for (ListIterator i = classList.listIterator(); i.hasNext();) {
if (i.next().equals(clazz)) {
i.remove();
}
}
}
}
/**
*
* Remove class attribute if it has no value.
* This method prevent no-meaning class attribute like below.
*
*
*
* <div class="">....</div>
*
*
*/
public void removeEmptyCssClass() {
RemoveEmptyCssClassUtil.removeEmptyCssClass(this);
}
/**
* find tag by "name" property returning as List.
* @param name
* @param tagType
* @param
* @return if not found, returns empty list.
*/
public List getByNameAsList(String name, Class tagType) {
return GetByNameUtil.getByNameAsList((T) this, new ArrayList(), name,tagType);
}
/**
* find tag by "name" property. (the first one in this tag)
*
* @param name
* @param tagType
* @param
* @return null if not found.
*/
public T getByName(String name, Class tagType) {
return GetByNameUtil.getByName((T) this, name, tagType);
}
/**
* get header tag
* @return
*/
public List getHeaderAsList() {
return this.getDescendants(Header.class);
}
/**
* get header tag (the first one in this tag)
* @return null if not found.
*/
public Header getHeader() {
List list = this.getDescendants(Header.class);
if (list.size() > 0) {
return list.get(0);
} else {
return null;
}
}
/**
* get footer tag
* @return
*/
public List