Skip to contentMethod: BeanListenerAspect.ManageableImpl()
1: /**
2: * Copyright (C) 2022 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.model;
16:
17: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
18: import cz.cvut.kbss.jopa.model.metamodel.EntityType;
19: import cz.cvut.kbss.jopa.model.metamodel.FieldSpecification;
20: import cz.cvut.kbss.jopa.sessions.UnitOfWorkImpl;
21: import cz.cvut.kbss.jopa.sessions.validator.AttributeModificationValidator;
22: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
23: import org.aspectj.lang.JoinPoint;
24: import org.aspectj.lang.annotation.*;
25: import org.aspectj.lang.reflect.FieldSignature;
26: import org.slf4j.Logger;
27: import org.slf4j.LoggerFactory;
28:
29: import java.io.Serializable;
30: import java.lang.reflect.Field;
31:
32: @Aspect
33: public class BeanListenerAspect {
34:
35: private static final Logger LOG = LoggerFactory.getLogger(BeanListenerAspect.class);
36:
37: public interface Manageable {
38: void setPersistenceContext(UnitOfWorkImpl uow);
39:
40: UnitOfWorkImpl getPersistenceContext();
41: }
42:
43: public static class ManageableImpl implements Manageable, Serializable {
44: private transient UnitOfWorkImpl persistenceContext;
45:
46: @Override
47: public void setPersistenceContext(UnitOfWorkImpl uow) {
48: this.persistenceContext = uow;
49: }
50:
51: @Override
52: public UnitOfWorkImpl getPersistenceContext() {
53: return persistenceContext;
54: }
55: }
56:
57: @DeclareMixin(value = "!is(InterfaceType) && (@cz.cvut.kbss.jopa.model.annotations.OWLClass *)")
58: public static Manageable createImpl() {
59: return new ManageableImpl();
60: }
61:
62: @Pointcut("get( @(cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty " +
63: "|| cz.cvut.kbss.jopa.model.annotations.OWLDataProperty " +
64: "|| cz.cvut.kbss.jopa.model.annotations.OWLAnnotationProperty " +
65: "|| cz.cvut.kbss.jopa.model.annotations.Types " +
66: "|| cz.cvut.kbss.jopa.model.annotations.Properties " +
67: "|| cz.cvut.kbss.jopa.model.annotations.Sparql) * * ) " +
68: "&& (within(@cz.cvut.kbss.jopa.model.annotations.OWLClass *) || within(@cz.cvut.kbss.jopa.model.annotations.MappedSuperclass *))")
69: void getter() {
70: }
71:
72: @Pointcut("set( @(cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty " +
73: "|| cz.cvut.kbss.jopa.model.annotations.OWLDataProperty " +
74: "|| cz.cvut.kbss.jopa.model.annotations.OWLAnnotationProperty " +
75: "|| cz.cvut.kbss.jopa.model.annotations.Types || cz.cvut.kbss.jopa.model.annotations.Properties ) * * ) " +
76: "&& (within(@cz.cvut.kbss.jopa.model.annotations.OWLClass *) || within(@cz.cvut.kbss.jopa.model.annotations.MappedSuperclass *))")
77: void setter() {
78: }
79:
80: /**
81: * Ties the specified instance to its persistence context, so that the advices can identify it easily.
82: *
83: * @param instance The managed instance
84: * @param persistenceContext Persistence context which is managing it
85: */
86: public void register(Object instance, UnitOfWorkImpl persistenceContext) {
87: ((Manageable) instance).setPersistenceContext(persistenceContext);
88: }
89:
90: /**
91: * Disconnects the specified instance from its persistence context.
92: *
93: * @param instance The instance to remove
94: * @see #register(Object, UnitOfWorkImpl)
95: */
96: public void deregister(Object instance) {
97: ((Manageable) instance).setPersistenceContext(null);
98: }
99:
100: @AfterReturning("setter()")
101: public void afterSetter(JoinPoint thisJoinPoint) {
102: // Persist changes done during transaction and check for inferred attribute modification
103: final Object entity = thisJoinPoint.getTarget();
104: if (!(entity instanceof Manageable)) {
105: return;
106: }
107: final UnitOfWorkImpl persistenceContext = ((Manageable) entity).getPersistenceContext();
108: if (persistenceContext == null || !persistenceContext.isInTransaction()) {
109: return;
110: }
111:
112: try {
113: final Field field = ((FieldSignature) thisJoinPoint.getSignature()).getField();
114: if (EntityPropertiesUtils.isFieldTransient(field)) {
115: return;
116: }
117: final FieldSpecification<?, ?> fieldSpec = getFieldSpecification(entity,
118: thisJoinPoint.getSignature().getName(), persistenceContext);
119: AttributeModificationValidator.verifyCanModify(fieldSpec);
120: persistenceContext.attributeChanged(entity, field);
121: } catch (SecurityException e) {
122: LOG.error(e.getMessage(), e);
123: throw new OWLPersistenceException(e.getMessage());
124: }
125: }
126:
127: private FieldSpecification<?, ?> getFieldSpecification(Object entity, String fieldName,
128: UnitOfWorkImpl persistenceContext) {
129: final EntityType<?> et = persistenceContext.getMetamodel().entity(entity.getClass());
130: assert et != null;
131: return et.getFieldSpecification(fieldName);
132: }
133:
134: @Before("getter()")
135: public void beforeGetter(JoinPoint thisJoinPoint) {
136: // Load lazy loaded entity field
137: final Object entity = thisJoinPoint.getTarget();
138: if (!(entity instanceof Manageable)) {
139: return;
140: }
141: final UnitOfWorkImpl persistenceContext = ((Manageable) entity).getPersistenceContext();
142: if (persistenceContext == null || !persistenceContext.contains(entity)) {
143: return;
144: }
145: final Field field = ((FieldSignature) thisJoinPoint.getSignature()).getField();
146: if (EntityPropertiesUtils.isFieldTransient(field)) {
147: return;
148: }
149: persistenceContext.loadEntityField(entity, field);
150: }
151: }