Please see my comments below .....
Tom > Get a handle on your EntityManagerFactory
(emf) and create an EntityManager for it (em1). em1 =
emf.createEntityManager()
Make a change to your data model that would cause the mappings to
change
Call emf.refreshMetadata() and confirm that your code that adds
mappings is getting called
Gaurav >> The above test case works
Tom > create an new EntityManager from emf.
em2 emf.createEntityManager()
Compare the mappings in em1 and em2. I would expect the changed
mappings to appear in em2.
Gaurav >> The above test case fails
On 25-07-2012 02:38 PM, Tom Ware wrote:
Let
me suggest a simple test:
Get a handle on your EntityManagerFactory (emf) and create an
EntityManager for it (em1). em1 = emf.createEntityManager()
Make a change to your data model that would cause the mappings to
change
Call emf.refreshMetadata() and confirm that your code that adds
mappings is getting called
create an new EntityManager from emf. em2
emf.createEntityManager()
Compare the mappings in em1 and em2. I would expect the changed
mappings to appear in em2.
On 25/07/2012 8:33 AM, gaurav malhotra wrote:
Hi Tom,
I also checked the spring entity manager creations
(JpaTemplate). Please see the
code below. getEntityManagerFactory() basically uses the same
entitymanager
factory, to which I added new mappings.
/**
* Create a close-suppressing proxy for the given JPA
EntityManager.
* The proxy also prepares returned JPA Query objects.
* @param em the JPA EntityManager to create a proxy for
* @return the EntityManager proxy, implementing all interfaces
* implemented by the passed-in EntityManager object (that is,
* also implementing all provider-specific extension interfaces)
* @see javax.persistence.EntityManager#close
*/
protected EntityManager createEntityManagerProxy(EntityManager
em) {
Class[] ifcs = null;
EntityManagerFactory emf = getEntityManagerFactory();
if (emf instanceof EntityManagerFactoryInfo) {
Class entityManagerInterface = ((EntityManagerFactoryInfo)
emf).getEntityManagerInterface();
if (entityManagerInterface != null) {
ifcs = new Class[] {entityManagerInterface};
}
}
if (ifcs == null) {
ifcs = ClassUtils.getAllInterfacesForClass(em.getClass());
}
return (EntityManager) Proxy.newProxyInstance(
em.getClass().getClassLoader(), ifcs, new
CloseSuppressingInvocationHandler(em));
}
On 25-07-2012 02:31 PM, gaurav malhotra wrote:
Hi Tom,
The issues currently I am facing are as follows
1) An application event (which is published on all the nodes
in the cluster -
coherence grid aware) is triggered when there is a need to
create a mapping.
(Works fine)
2) I have service named DynamicRecordWeaverImpl which creates
the mappings as
follows (Please verify, if below correct way of adding
mappings. As chris
mentioned I am not creating mapping on active session)
NOTE >> after weave method, I can see the need added
relationship in the session.
@Autowired
private DynamicRecordContext dynamicRecordContext;
@Autowired
@Qualifier("entityManagerFactory")
private LocalContainerEntityManagerFactoryBean
localContainerEntityManagerFactoryBean;
/*
* (non-Javadoc)
* @see
com.oracle.healthinsurance.common.domain.internal.dyndata.components.DynamicRecordWeaver#weave()
*/
@SuppressWarnings("rawtypes")
@Override
public void weave() {
JpaEntityManagerFactory jpaEntityManagerFactory =
JpaEntityManagerFactory.class.cast(localContainerEntityManagerFactoryBean
.getNativeEntityManagerFactory());
Session session = jpaEntityManagerFactory.getServerSession();
for (Map.Entry<Class, ClassDescriptor> entry :
session.getDescriptors().entrySet()) {
if (MetaModelUtil.isDynamicRecordContainer(entry.getKey())) {
Class<? extends
DynamicRecordContainer<DynamicRecordStorable>>
dynamicRecordContainerClass = CastUtil
.uncheckedCast(entry.getKey());
Class<? extends DynamicRecordStorable>
dynamicRecordStorableClass = CastUtil
.uncheckedCast(GenericTypeResolver.resolveTypeArgument(dynamicRecordContainerClass,
DynamicRecordContainer.class));
ClassDescriptor dynamicRecordContainerClassCd =
session.getDescriptor(dynamicRecordContainerClass);
ClassDescriptor dynamicRecordStorableClassCd =
session.getDescriptor(EclipseLinkMetadata
.getDomainClass(dynamicRecordStorableClass));
Map<String, DynamicRecordSetup> dynamicRecordSetupMap =
dynamicRecordContext
.doGetDynamicRecordsSetup(dynamicRecordContainerClass);
for (Map.Entry<String, DynamicRecordSetup> setupEntry :
dynamicRecordSetupMap.entrySet()) {
String fieldName = setupEntry.getKey();
DynamicRecordSetup dynamicRecordSetup = setupEntry.getValue();
// OneToMany
oneToManyMapping(dynamicRecordContainerClassCd, fieldName,
dynamicRecordStorableClassCd.getJavaClass());
for (FieldDetails fieldDetails :
dynamicRecordSetup.getFieldDetailsList()) {
// Add the attributes dynamicRecordStorableClass
String attributeName = fieldDetails.getCode();
String columnName = columnName(fieldDetails);
Class<?> attributeType = attributeType(fieldDetails);
directFieldMapping(dynamicRecordStorableClassCd,
attributeName, columnName,
attributeType);
}
}
}
}
jpaEntityManagerFactory.refreshMetadata(null);
System.gc();
3) You mentioned >> " The way refreshMetadata works,
should allow your system
to stay live. When you call refreshMetadata, all existing
EntityManagers
continue to operate on the previous metadata. The new metadata
is only in
effect for new EntityManagers. "
Now I am searching for entity to which new mappings where
added. What I found
that entityManager does not contain the newly added mappings.
I cann't figure
out why?? It should be picked up?? so do I have keep adding
the mappings for
each session and call refreshMetadata, this doen't look
elegant. Is some where
there is caching of entity managers happening???
On 25-07-2012 01:56 PM, Tom Ware wrote:
Hi Gaurav,
I am assuming you've figured out how to get refreshMetadata
to work for you
to get your mappings added. EclipseLink itself does not
provide a mechanism
to trigger the refresh There are a number of options open to
you depending on
how your app is architected, JMS, RMI, ServerSentEvents,
WebSockets, Oracle
QCN/DCN combined with one of those technologies.
The way refreshMetadata works, should allow your system to
stay live. When
you call refreshMetadata, all existing EntityManagers
continue to operate on
the previous metadata. The new metadata is only in effect
for new
EntityManagers.
-Tom
On 24/07/2012 8:12 PM, gaurav malhotra wrote:
I understand the problem, but I
don't know how to fix it.
1) I am recording all the changes (we store them in the
database)
2) I don't know how to signal that session needs to pick
them using
refreshMetadata. Does this mean using
SessionEventAdapter?? If yes then which
method(s) should I use. As per my understanding
refreshMetadata should be only
called once if there are recorded changes. When recorded
changes has been
pushed
to session, then there is no need to refreshMetadata. It
will be great if you
point me some code snippets.
Also, my product, is a claim processing system (with
millions of transactions
handled in a day). What is the impact of refreshMetadata
on the running
transactions?? We dont expect setup for the dynamic fields
change every another
minute or a day??
On 25-07-2012 12:04 AM, Christopher Delahunt wrote:
Through a metadata source
repository, or the customizer approach. Your app
must record the changes that are needed somehow and then
signal that the
session needs to pick them up using refreshMetadata. The
app should not
directly change the running session.
On 2012-07-24, at 5:47 PM, gaurav malhotra
<gaurav.malhotra@xxxxxxxxxx> wrote:
Hi Chris,
It's the requirement of my product - Dynamic Fields
can be configured at the
runtime and should be picked up in live application
with zero down time. Its
for the dynamic fields I am creating the mappings.
How to accomplish above reqirement?
~Gaurav
On 24-07-2012 11:29 PM, Christopher Delahunt wrote:
This would occur if the
mapping has not been initialized; initialization
occurs during session login. Earlier posts showed
mappings being added
through a session customizer which get called prior
to login. How and when
is this mapping added?
Calling refreshMetadata as Tom mentions creates a
new session from the
metadata, and would call customizers on it before
logging in. If your
customizer picks up the new mapping changes, then
that might explain why it
works for you, since they get initialized with the
new session login.
It is not a good idea to make mapping/descriptor
changes to active sessions
after login has occurred.
On 24/07/2012 5:05 PM, gaurav malhotra wrote:
ava.lang.NullPointerException
at
org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRowInternal(ForeignReferenceMapping.java:2019)
at
org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRow(ForeignReferenceMapping.java:1987)
at
org.eclipse.persistence.mappings.ForeignReferenceMapping.buildCloneFromRow(ForeignReferenceMapping.java:276)
at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoWorkingCopyClone(ObjectBuilder.java:1548)
at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuilder.java:1694)
at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:664)
at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:601)
at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:560)
at
org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:717)
at
org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:769)
_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users
_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users
|