Java tutorial
/*$Id: FieldImpl.java 15337 2010-03-09 09:24:54Z jens $*/ /* **************************************************************************** * * * (c) Copyright 2009 ABM-utvikling * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 2 of the License, or (at your * * option) any later version. * * * * This program 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 General * * Public License for more details. http://www.gnu.org/licenses/gpl.html * * * **************************************************************************** */ package no.abmu.questionnaire.domain.metadata; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.persistence.CascadeType; import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; import no.abmu.questionnaire.domain.constants.DbSchemaNameConst; import no.abmu.questionnaire.domain.data.DomainObject; import no.abmu.questionnaire.domain.data.FieldData; import no.abmu.questionnaire.domain.types.SchoolHas; import no.abmu.questionnaire.domain.validators.FieldValidator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.Index; import org.hibernate.annotations.Type; /** * Implements interface Field. * * @author Aase Mestad * @author $Author: jens $ * @version $Rev: 15337 $ * @date $Date: 2010-03-09 10:24:54 +0100 (Tue, 09 Mar 2010) $ * @copyright ABM-Utvikling */ @SuppressWarnings("serial") @Entity @Table(name = "BASEFIELD", schema = DbSchemaNameConst.QUESTIONNAIRE_DB_SCHEMA_NAME) @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "discriminatorValue", length = 35, discriminatorType = DiscriminatorType.STRING) //@ForceDiscriminator //@Inheritance(strategy=InheritanceType.JOINED) @Cache(usage = CacheConcurrencyStrategy.READ_ONLY) public abstract class FieldImpl extends DomainObject implements Field { private static final Log logger = (Log) LogFactory.getLog(FieldImpl.class); private String code; private String fieldName; private String fieldDescription; private Date periodFrom; private Date periodTo; private Account account; private Set validators = new HashSet(); private FieldPeriod period; private FieldType type; private boolean finishField = false; public FieldImpl() { } public FieldImpl(String code, FieldPeriod period, FieldType type) { this.code = code; this.period = period; this.type = type; } public String getCode() { return code; } public String getFieldName() { return fieldName; } public void setFieldName(String fieldName) { this.fieldName = fieldName; } public String getFieldDescription() { return fieldDescription; } public void setFieldDescription(String fieldDescription) { this.fieldDescription = fieldDescription; } @Type(type = "no.abmu.util.hibernate3.DateType") public Date getPeriodFrom() { return periodFrom; } public void setPeriodFrom(Date periodFrom) { this.periodFrom = periodFrom; } @Type(type = "no.abmu.util.hibernate3.DateType") public Date getPeriodTo() { return periodTo; } public void setPeriodTo(Date periodTo) { this.periodTo = periodTo; } public boolean isFinishField() { return finishField; } public void setFinishField(Boolean finishField) { this.finishField = finishField; } /** * This helper method initializes the extra properties like stringLength in StringField. * * @param arguments the values for properties in fields */ protected abstract void initialize(String[] arguments); public void setCode(String code) { this.code = code; } @ManyToOne(targetEntity = Account.class) @Index(name = "field_account_fk_idx") @JoinColumn(name = "FK_ACCOUNT_ID", insertable = false, updatable = false) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) public Account getAccount() { return account; } public void setAccount(Account account) { this.account = account; } @ManyToOne(cascade = CascadeType.ALL) public FieldType getType() { return type; } public void setType(FieldType type) { this.type = type; } @ManyToOne(cascade = CascadeType.ALL) public FieldPeriod getPeriod() { return period; } public void setPeriod(FieldPeriod period) { this.period = period; } /* @OneToMany(targetEntity = FieldValidator.class, cascade = CascadeType.ALL, fetch=FetchType.EAGER) @JoinTable( name = "FIELD_FIELDVALIDATOR", schema = DbSchemaNameConst.QUESTIONNAIRE_DB_SCHEMA_NAME, joinColumns = @JoinColumn(name = "FK_FIELD_ID"), inverseJoinColumns = @JoinColumn(name = "FK_FIELDVALIDATOR_ID")) */ @OneToMany(cascade = CascadeType.ALL, targetEntity = FieldValidator.class, fetch = FetchType.EAGER) @JoinColumn(name = "FK_FIELD_ID") @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) // @Fetch(FetchMode.SUBSELECT) public Set getValidators() { return validators; } public void setValidators(Set<FieldValidator> validators) { this.validators = validators; } public void addValidator(FieldValidator validator) { validators.add(validator); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } FieldImpl field = (FieldImpl) o; if (account != null ? !account.equals(field.account) : field.account != null) { return false; } if (code != null ? !code.equals(field.code) : field.code != null) { return false; } if (period != null ? !period.equals(field.period) : field.period != null) { return false; } // if (schem != null ? !schema.equals(field.schema) : field.schema != null) { // return false; // } if (type != null ? !type.equals(field.type) : field.type != null) { return false; } return true; } @Override public int hashCode() { int result = code != null ? code.hashCode() : 0; result = 31 * result + (account != null ? account.hashCode() : 0); result = 31 * result + (period != null ? period.hashCode() : 0); result = 31 * result + (type != null ? type.hashCode() : 0); // result = 31 * result + (schema != null ? schema.hashCode() : 0); return result; } public abstract FieldData createFieldData(); /** * FieldFactory. * */ public static final class FieldFactory { private static HashMap<String, Class> fieldClassMap; private static String patternStr = "(.+)\\((.+)\\)"; private static Pattern pattern = Pattern.compile(patternStr); // Suppress default constructor for noninstantiability private FieldFactory() { // This constructor will never be invoked. // See Item 3 on page 12 in // Joshua Bloch: Effective Java: Programming Language Guide, 2001 // ISBN 0-201-31005-8 } private static HashMap<String, Class> initializeFieldClassMap() { HashMap<String, Class> map = new HashMap<String, Class>(); map.put("string", StringField.class); map.put("boolean", BooleanField.class); map.put("yesnopartly", YesNoPartlyField.class); map.put("decimal", BigDecimalField.class); map.put("long", LongField.class); map.put("skolenssamlinger", SkolensSamlingerField.class); map.put("hovedomraade", MuseumHovedOmraadeField.class); map.put("organizationform", MuseumOrganizationFormField.class); map.put("date", DateField.class); map.put("fireorfirestart", FireOrFireStartField.class); map.put("theftortheftattempt", TheftOrTheftAttemptField.class); map.put("discoveryoffire", DiscoveryOfFireField.class); map.put("extinguishmethod", ExtinguishMethodField.class); map.put("reasonoffire", ReasonOfFireField.class); map.put("whoextinguished", WhoExtinguishedField.class); map.put("schoolhas", SchoolHasField.class); return map; } /** * Parses the input string to find arguments to the class in * parentheses at the end of the string. String and Decimal * accepts arguments. * * @param fieldClassNameAndArgs String with code to lookup * the proper class and arguments to initialize the class. * @return an array of Strings with the parsed arguments. */ private static String[] getArguments(String fieldClassNameAndArgs) { Matcher matcher = pattern.matcher(fieldClassNameAndArgs); if (!matcher.matches()) { return null; } String args = matcher.group(2); return args.split(","); } /** * Looks up the proper class from fieldClassMap. Some classes needs * to be initialized, these parameters are in parentheses at the end * of the string. String and Decimal expect one argument each, the * other classes expects no arguments. If a class expects several * arguments, these are separated by comma. * * @param fieldClassNameAndArgs code to look up the proper class and * argument to initialize the class. * @param name name of field * @param code string with two or three digits that identifies the field uniquely within a schema. * @return instantiated field */ public static FieldImpl createField(String fieldClassNameAndArgs, String name, String code, Schema schema) { if (fieldClassMap == null) { fieldClassMap = initializeFieldClassMap(); } String[] arguments = getArguments(fieldClassNameAndArgs); String className = null; if (arguments == null) { className = fieldClassNameAndArgs; } else { className = fieldClassNameAndArgs.substring(0, fieldClassNameAndArgs.indexOf("(")); } Class clazz = fieldClassMap.get(className.toLowerCase()); if (clazz == null) { String message = "Can not find class name for field with argument=[" + fieldClassNameAndArgs + "]."; logger.error(message); throw new RuntimeException(message); } try { FieldImpl field = (FieldImpl) clazz.newInstance(); if (arguments != null) { field.initialize(arguments); } // field.setSchema(schema); field.setCode(code); return field; } catch (InstantiationException e) { String message = "Exception when creating class " + clazz.getName(); logger.error(message, e.getCause()); throw new RuntimeException(message, e.getCause()); } catch (IllegalAccessException e) { String message = "The class " + clazz.getName() + " did not have a public empty constructor"; logger.error(message, e.getCause()); throw new RuntimeException(message, e.getCause()); } } } }