/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache license, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.internna.iwebmvc.model.core;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.FieldBridge;
import org.hibernate.search.annotations.Indexed;
import org.internna.iwebmvc.core.context.ContextHolder;
import org.internna.iwebmvc.core.hibernate.UUIDFieldBridge;
import org.internna.iwebmvc.core.visitor.AnnotationVisitor;
import org.internna.iwebmvc.core.visitor.FieldVisitor;
import org.internna.iwebmvc.core.visitor.VisitException;
import org.internna.iwebmvc.model.DomainEntity;
import org.internna.iwebmvc.model.Feedable;
import org.internna.iwebmvc.model.Searchable;
import org.internna.iwebmvc.model.UUID;
import org.internna.iwebmvc.utils.BeanUtils;
import org.internna.iwebmvc.utils.ClassUtils;
import org.internna.iwebmvc.utils.StringUtils;
/**
* Basic implementation of a JPA entity.
*
* @author Jose Noheda
* @since 1.0
*/
@MappedSuperclass
public abstract class AbstractDomainEntity implements DomainEntity, Serializable {
@Transient protected Log log = LogFactory.getLog(getClass());
@Id
@DocumentId
@FieldBridge(impl = UUIDFieldBridge.class)
@Column(name = "ID", length = 16)
@GeneratedValue(generator = "uuid")
@Type(type = "org.internna.iwebmvc.model.hibernate.UUIDType")
@GenericGenerator(name = "uuid", strategy = "org.internna.iwebmvc.core.hibernate.UUIDGenerator")
private UUID id;
@Override
public UUID getId() {
return id;
}
@Override
public void setId(UUID id) {
this.id = id;
}
@Override
@SuppressWarnings("unchecked")
public <T> T accept(AnnotationVisitor visitor) {
AbstractDomainEntity clone = BeanUtils.copyProperties(this, Arrays.asList("primaryKey"));
Class<? extends Annotation> a = visitor.baseAnnotation();
for (PropertyDescriptor propertyDescriptor : org.springframework.beans.BeanUtils.getPropertyDescriptors(this.getClass())) {
try {
Method getter = propertyDescriptor.getReadMethod();
if ((getter != null) && (getter.getAnnotation(a) != null) && (propertyDescriptor.getWriteMethod() != null))
propertyDescriptor.getWriteMethod().invoke(clone, visitor.visit(getter.invoke(this)));
} catch (Exception ex) {
throw new VisitException("Exception visiting [" + propertyDescriptor.getName() + "]", ex);
}
}
return (T) clone;
}
@Override
@SuppressWarnings("unchecked")
public <T> T accept(final FieldVisitor visitor) {
Collection<Object> results = new ArrayList<Object>();
for (Field field : ClassUtils.getFields(this.getClass())) {
try {
field.setAccessible(true);
results.addAll(visitor.visit(field, field.get(this)));
} catch (Exception ex) {
throw new VisitException("Exception visiting [" + field + "]", ex);
}
}
return (T) results;
}
@Override
public boolean isIndexed() {
return getClass().getAnnotation(Indexed.class) != null;
}
public boolean isFeedable() {
return Feedable.class.isInstance(this);
}
public boolean isSearchable() {
return Searchable.class.isAssignableFrom(getClass());
}
@Override
public void initialize(ContextHolder context) {
return;
}
public List<Field> getFields(String[] fields) {
List<Field> l = new ArrayList<Field>();
for (String field : fields) {
try {
if (StringUtils.hasText(field)) l.add(getClass().getDeclaredField(field));
} catch (Exception ex) {
if (log.isWarnEnabled()) log.warn("Field [" + field + "] does not exist in [" + getClass().getName() + "]");
}
}
return l;
}
@Override
public boolean equals(Object obj) {
boolean eq = false;
if ((obj != null) && AbstractDomainEntity.class.isInstance(obj)) {
AbstractDomainEntity o = (AbstractDomainEntity) obj;
if ((getId() != null) & (o.getId() != null)) {
eq = getId().toString().equals(o.getId().toString());
}
}
return eq ? eq : super.equals(obj);
}
@Override
public int hashCode() {
return id != null ? id.toString().hashCode() : super.hashCode();
}
public String rssQuery() {
return getClass().getSimpleName() + ".rss";
}
@Override
public String selectableQuery() {
return "SELECT id, name FROM " + getClass().getSimpleName() + " WHERE name LIKE :query";
}
public Boolean isI18n() throws Exception {
return isI18n(0);
}
protected Boolean isI18n(int depth) throws Exception {
boolean isi18n = false;
if (depth < 10) { // Prevent endless circular loops
Collection<Field> fields = ClassUtils.getFields(getClass());
for (Field f : fields) {
if (!isi18n) {
Class<?> fieldClass = f.getType();
if (Collection.class.isAssignableFrom(fieldClass)) fieldClass = ClassUtils.getGenericType(f);
if (I18nText.class.isAssignableFrom(fieldClass)) isi18n = true;
else if (AbstractDomainEntity.class.isAssignableFrom(fieldClass)) {
isi18n = ((AbstractDomainEntity) fieldClass.newInstance()).isI18n(depth + 1);
}
}
}
}
return isi18n;
}
}