You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2014/05/02 19:22:29 UTC
[1/4] ISIS-772: reimplemented.
Repository: isis
Updated Branches:
refs/heads/master 72a191183 -> 074d2c4e4
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryAbstractTest_wrappedObject.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryAbstractTest_wrappedObject.java b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryAbstractTest_wrappedObject.java
new file mode 100644
index 0000000..1d38027
--- /dev/null
+++ b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryAbstractTest_wrappedObject.java
@@ -0,0 +1,380 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.progmodel.wrapper;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+
+import org.jmock.Expectations;
+import org.jmock.auto.Mock;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import org.apache.isis.applib.services.wrapper.DisabledException;
+import org.apache.isis.applib.services.wrapper.HiddenException;
+import org.apache.isis.applib.services.wrapper.InvalidException;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
+import org.apache.isis.core.metamodel.adapter.QuerySubmitter;
+import org.apache.isis.core.metamodel.adapter.ResolveState;
+import org.apache.isis.core.metamodel.adapter.ServicesProvider;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facets.FacetedMethod;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMemberContext;
+import org.apache.isis.core.metamodel.specloader.collectiontyperegistry.CollectionTypeRegistryDefault;
+import org.apache.isis.core.metamodel.specloader.specimpl.OneToOneAssociationImpl;
+import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
+import org.apache.isis.core.progmodel.facets.members.disabled.method.DisableForContextFacetViaMethod;
+import org.apache.isis.core.progmodel.facets.members.hidden.method.HideForContextFacetViaMethod;
+import org.apache.isis.core.progmodel.facets.members.named.staticmethod.NamedFacetViaMethod;
+import org.apache.isis.core.progmodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor;
+import org.apache.isis.core.progmodel.facets.properties.modify.PropertyClearFacetViaClearMethod;
+import org.apache.isis.core.progmodel.facets.properties.modify.PropertyInitializationFacetViaSetterMethod;
+import org.apache.isis.core.progmodel.facets.properties.modify.PropertySetterFacetViaModifyMethod;
+import org.apache.isis.core.progmodel.facets.properties.modify.PropertySetterFacetViaSetterMethod;
+import org.apache.isis.core.progmodel.facets.properties.validate.PropertyValidateFacetViaMethod;
+import org.apache.isis.core.runtime.authentication.standard.SimpleSession;
+import org.apache.isis.core.tck.dom.claimapp.employees.Employee;
+import org.apache.isis.core.tck.dom.claimapp.employees.EmployeeRepository;
+import org.apache.isis.core.tck.dom.claimapp.employees.EmployeeRepositoryImpl;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.apache.isis.core.wrapper.WrapperFactoryAbstract;
+
+public abstract class WrapperFactoryAbstractTest_wrappedObject {
+
+ @Rule
+ public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Mock
+ private AdapterManager mockAdapterManager;
+ @Mock
+ private AuthenticationSessionProvider mockAuthenticationSessionProvider;
+ @Mock
+ private ObjectPersistor mockObjectPersistor;
+ @Mock
+ private QuerySubmitter mockQuerySubmitter;
+ @Mock
+ private ServicesProvider mockServicesProvider;
+ @Mock
+ private SpecificationLoader mockSpecificationLookup;
+
+ private ObjectMemberContext objectMemberContext;
+
+ @Mock
+ private ObjectSpecificationDefault mockEmployeeSpec;
+ private ObjectMember employeeNameMember;
+
+ @Mock
+ private ObjectSpecificationDefault mockStringSpec;
+
+ @Mock
+ private ObjectAdapter mockEmployeeAdapter;
+
+ @Mock
+ private ObjectAdapter mockAdapterForStringSmith;
+ @Mock
+ private ObjectAdapter mockAdapterForStringJones;
+
+ private final SimpleSession session = new SimpleSession("tester", Collections.<String>emptyList());
+
+ private EmployeeRepository employeeRepository;
+
+ private Employee employeeDO;
+ private Employee employeeWO;
+
+ private WrapperFactoryAbstract wrapperFactory;
+
+
+
+
+ @Before
+ public void setUp() {
+
+ objectMemberContext = new ObjectMemberContext(DeploymentCategory.PRODUCTION, mockAuthenticationSessionProvider, mockSpecificationLookup, mockAdapterManager, mockQuerySubmitter, new CollectionTypeRegistryDefault(), mockServicesProvider);
+
+ employeeRepository = new EmployeeRepositoryImpl();
+
+ employeeDO = new Employee();
+ employeeDO.setName("Smith");
+ employeeDO.setEmployeeRepository(employeeRepository);
+
+ wrapperFactory = createWrapperFactory();
+ wrapperFactory.setAdapterManager(mockAdapterManager);
+ wrapperFactory.setAuthenticationSessionProvider(mockAuthenticationSessionProvider);
+ wrapperFactory.setObjectPersistor(mockObjectPersistor);
+ wrapperFactory.setSpecificationLookup(mockSpecificationLookup);
+
+ context.checking(new Expectations() {
+ {
+ allowing(mockSpecificationLookup).loadSpecification(String.class);
+ will(returnValue(mockStringSpec));
+
+ allowing(mockStringSpec).getShortIdentifier();
+ will(returnValue(String.class.getName()));
+ }
+ });
+
+
+ final Method employeeGetNameMethod = methodOf(Employee.class, "getName");
+ final Method employeeSetNameMethod = methodOf(Employee.class, "setName", String.class);
+ final Method employeeModifyNameMethod = methodOf(Employee.class, "modifyName", String.class);
+ final Method employeeHideNameMethod = methodOf(Employee.class, "hideName");
+ final Method employeeDisableNameMethod = methodOf(Employee.class, "disableName");
+ final Method employeeValidateNameMethod = methodOf(Employee.class, "validateName", String.class);
+ final Method employeeClearNameMethod = methodOf(Employee.class, "clearName");
+ employeeNameMember = new OneToOneAssociationImpl(
+ facetedMethodForProperty(
+ employeeSetNameMethod, employeeGetNameMethod, employeeModifyNameMethod, employeeClearNameMethod, employeeHideNameMethod, employeeDisableNameMethod, employeeValidateNameMethod), objectMemberContext);
+
+ context.checking(new Expectations() {
+ {
+ allowing(mockAuthenticationSessionProvider).getAuthenticationSession();
+ will(returnValue(session));
+
+ allowing(mockAdapterManager).getAdapterFor(employeeDO);
+ will(returnValue(mockEmployeeAdapter));
+
+ allowing(mockEmployeeAdapter).getSpecification();
+ will(returnValue(mockEmployeeSpec));
+
+ allowing(mockSpecificationLookup).loadSpecification(Employee.class);
+ will(returnValue(mockEmployeeSpec));
+
+ allowing(mockEmployeeSpec).getMember(methodOf(Employee.class, "getEmployeeRepository"));
+ will(returnValue(null));
+
+ allowing(mockEmployeeSpec).getMember(employeeGetNameMethod);
+ will(returnValue(employeeNameMember));
+
+ allowing(mockEmployeeSpec).getMember(employeeSetNameMethod);
+ will(returnValue(employeeNameMember));
+
+ allowing(mockEmployeeSpec).getMember(employeeModifyNameMethod);
+ will(returnValue(employeeNameMember));
+
+ allowing(mockEmployeeSpec).getMember(employeeClearNameMethod);
+ will(returnValue(employeeNameMember));
+
+ allowing(mockEmployeeAdapter).getObject();
+ will(returnValue(employeeDO));
+
+ allowing(mockEmployeeAdapter).representsPersistent();
+ will(returnValue(true));
+ }
+ });
+
+
+ employeeWO = wrapperFactory.wrap(employeeDO);
+ }
+
+ /**
+ * Mandatory hook.
+ */
+ protected abstract WrapperFactoryAbstract createWrapperFactory();
+
+ @Test
+ public void shouldWrapDomainObject() {
+ // then
+ assertThat(employeeWO, is(notNullValue()));
+ }
+
+ @Test
+ public void shouldBeAbleToInjectIntoDomainObjects() {
+ assertThat(employeeDO.getEmployeeRepository(), is(notNullValue()));
+ }
+
+ @Test
+ public void cannotAccessMethodNotCorrespondingToMember() {
+
+ expectedException.expectMessage("Method 'getEmployeeRepository' being invoked does not correspond to any of the object's fields or actions.");
+
+ // then
+ assertThat(employeeWO.getEmployeeRepository(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldBeAbleToReadVisibleProperty() {
+
+ allowingEmployeeHasSmithAdapter();
+
+
+ // then
+ assertThat(employeeWO.getName(), is(employeeDO.getName()));
+ }
+
+ @Test
+ public void shouldNotBeAbleToViewHiddenProperty() {
+
+ expectedException.expect(HiddenException.class);
+
+ allowingEmployeeHasSmithAdapter();
+
+ // given
+ employeeDO.whetherHideName = true;
+ // when
+ employeeWO.getName();
+ // then should throw exception
+ }
+
+ @Test
+ public void shouldBeAbleToModifyEnabledPropertyUsingSetter() {
+
+ allowingJonesStringValueAdapter();
+
+ context.checking(new Expectations() {
+ {
+
+ oneOf(mockAdapterManager).adapterFor("Jones", mockEmployeeAdapter);
+ will(returnValue(mockAdapterForStringJones));
+ }
+ });
+
+ // when
+ employeeWO.setName("Jones");
+ // then
+ assertThat(employeeDO.getName(), is("Jones"));
+ assertThat(employeeWO.getName(), is(employeeDO.getName()));
+ }
+
+ @Test
+ public void shouldNotBeAbleToModifyDisabledProperty() {
+
+ expectedException.expect(DisabledException.class);
+
+ // given
+ employeeDO.reasonDisableName = "sorry, no change allowed";
+ // when
+ employeeWO.setName("Jones");
+ // then should throw exception
+ }
+
+ @Test
+ public void shouldNotBeAbleToModifyPropertyUsingModify() {
+
+ allowingJonesStringValueAdapter();
+
+ expectedException.expect(UnsupportedOperationException.class);
+
+ // when
+ employeeWO.modifyName("Jones");
+ // then should throw exception
+ }
+
+ @Test
+ public void shouldNotBeAbleToModifyPropertyUsingClear() {
+
+ expectedException.expect(UnsupportedOperationException.class);
+
+ // when
+ employeeWO.clearName();
+ // then should throw exception
+ }
+
+ @Test
+ public void shouldNotBeAbleToModifyPropertyIfInvalid() {
+
+ allowingJonesStringValueAdapter();
+
+ expectedException.expect(InvalidException.class);
+
+ // given
+ employeeDO.reasonValidateName = "sorry, invalid data";
+ // when
+ employeeWO.setName("Jones");
+ // then should throw exception
+ }
+
+
+ // //////////////////////////////////////
+
+ private static FacetedMethod facetedMethodForProperty(
+ Method init, Method accessor, Method modify, Method clear, Method hide, Method disable, Method validate) {
+ FacetedMethod facetedMethod = FacetedMethod.createForProperty(accessor.getDeclaringClass(), accessor);
+ FacetUtil.addFacet(new PropertyAccessorFacetViaAccessor(accessor, facetedMethod));
+ FacetUtil.addFacet(new PropertyInitializationFacetViaSetterMethod(init, facetedMethod));
+ FacetUtil.addFacet(new PropertySetterFacetViaModifyMethod(modify, facetedMethod));
+ FacetUtil.addFacet(new PropertyClearFacetViaClearMethod(clear, facetedMethod));
+ FacetUtil.addFacet(new HideForContextFacetViaMethod(hide, facetedMethod));
+ FacetUtil.addFacet(new DisableForContextFacetViaMethod(disable, facetedMethod));
+ FacetUtil.addFacet(new PropertyValidateFacetViaMethod(validate, facetedMethod));
+ FacetUtil.addFacet(new NamedFacetViaMethod(accessor.getName(), accessor, facetedMethod));
+ return facetedMethod;
+ }
+
+ private static Method methodOf(Class<?> cls, String methodName) {
+ return methodOf(cls, methodName, new Class<?>[]{});
+ }
+
+ private static Method methodOf(Class<?> cls, String methodName, Class<?>... args) {
+ try {
+ return cls.getMethod(methodName, args);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // //////////////////////////////////////
+
+ private void allowingEmployeeHasSmithAdapter() {
+ context.checking(new Expectations() {
+ {
+ allowing(mockAdapterManager).adapterFor("Smith", mockEmployeeAdapter);
+ will(returnValue(mockAdapterForStringSmith));
+
+ allowing(mockAdapterForStringSmith).getObject();
+ will(returnValue("Smith"));
+ }
+ });
+ }
+
+ private void allowingJonesStringValueAdapter() {
+ context.checking(new Expectations() {
+ {
+ allowing(mockAdapterManager).adapterFor("Jones");
+ will(returnValue(mockAdapterForStringJones));
+
+ allowing(mockAdapterForStringJones).getObject();
+ will(returnValue("Jones"));
+
+ allowing(mockAdapterForStringJones).isTransient();
+ will(returnValue(ResolveState.VALUE.isTransient()));
+ }
+ });
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryAbstractTest_wrappedObject_transient.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryAbstractTest_wrappedObject_transient.java b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryAbstractTest_wrappedObject_transient.java
new file mode 100644
index 0000000..3d2d984
--- /dev/null
+++ b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryAbstractTest_wrappedObject_transient.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.progmodel.wrapper;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.jmock.Expectations;
+import org.jmock.auto.Mock;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.events.PropertyModifyEvent;
+import org.apache.isis.applib.events.PropertyUsabilityEvent;
+import org.apache.isis.applib.events.PropertyVisibilityEvent;
+import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.applib.services.wrapper.DisabledException;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.consent.Allow;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.InteractionResult;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
+import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet;
+import org.apache.isis.core.progmodel.facets.members.disabled.staticmethod.DisabledFacetAlwaysEverywhere;
+import org.apache.isis.core.progmodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor;
+import org.apache.isis.core.progmodel.facets.properties.modify.PropertySetterFacetViaSetterMethod;
+import org.apache.isis.core.runtime.authentication.standard.SimpleSession;
+import org.apache.isis.core.tck.dom.claimapp.employees.Employee;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.apache.isis.core.wrapper.WrapperFactoryAbstract;
+import org.apache.isis.core.wrapper.WrapperFactoryDefault;
+
+/**
+ * Contract test.
+ */
+public abstract class WrapperFactoryAbstractTest_wrappedObject_transient {
+
+ @Rule
+ public final JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+
+ @Mock
+ private AdapterManager mockAdapterManager;
+ @Mock
+ private AuthenticationSessionProvider mockAuthenticationSessionProvider;
+ @Mock
+ private ObjectPersistor mockObjectPersistor;
+ @Mock
+ private SpecificationLoader mockSpecificationLookup;
+
+ private Employee employeeDO;
+ @Mock
+ private ObjectAdapter mockEmployeeAdapter;
+ @Mock
+ private ObjectSpecificationDefault mockEmployeeSpec;
+ @Mock
+ private OneToOneAssociation mockPasswordMember;
+ @Mock
+ private Identifier mockPasswordIdentifier;
+
+ @Mock
+ protected ObjectAdapter mockPasswordAdapter;
+
+ private final String passwordValue = "12345678";
+
+ private final SimpleSession session = new SimpleSession("tester", Collections.<String>emptyList());
+
+ private List<Facet> facets;
+ private Method getPasswordMethod;
+ private Method setPasswordMethod;
+
+ private WrapperFactoryAbstract wrapperFactory;
+ private Employee employeeWO;
+
+
+ @Before
+ public void setUp() throws Exception {
+
+ employeeDO = new Employee();
+ employeeDO.setName("Smith");
+
+ getPasswordMethod = Employee.class.getMethod("getPassword");
+ setPasswordMethod = Employee.class.getMethod("setPassword", String.class);
+
+ wrapperFactory = createWrapperFactory();
+ wrapperFactory.setAdapterManager(mockAdapterManager);
+ wrapperFactory.setAuthenticationSessionProvider(mockAuthenticationSessionProvider);
+ wrapperFactory.setObjectPersistor(mockObjectPersistor);
+ wrapperFactory.setSpecificationLookup(mockSpecificationLookup);
+
+ context.checking(new Expectations() {
+ {
+ allowing(mockAdapterManager).getAdapterFor(employeeDO);
+ will(returnValue(mockEmployeeAdapter));
+
+ allowing(mockAdapterManager).adapterFor(passwordValue);
+ will(returnValue(mockPasswordAdapter));
+
+ allowing(mockEmployeeAdapter).getSpecification();
+ will(returnValue(mockEmployeeSpec));
+
+ allowing(mockEmployeeAdapter).getObject();
+ will(returnValue(employeeDO));
+
+ allowing(mockPasswordAdapter).getObject();
+ will(returnValue(passwordValue));
+
+ allowing(mockPasswordMember).getIdentifier();
+ will(returnValue(mockPasswordIdentifier));
+
+ allowing(mockSpecificationLookup).loadSpecification(Employee.class);
+ will(returnValue(mockEmployeeSpec));
+
+ allowing(mockEmployeeSpec).getMember(with(setPasswordMethod));
+ will(returnValue(mockPasswordMember));
+
+ allowing(mockEmployeeSpec).getMember(with(getPasswordMethod));
+ will(returnValue(mockPasswordMember));
+
+ allowing(mockPasswordMember).getName();
+ will(returnValue("password"));
+
+ allowing(mockAuthenticationSessionProvider).getAuthenticationSession();
+ will(returnValue(session));
+
+ allowing(mockPasswordMember).isOneToOneAssociation();
+ will(returnValue(true));
+
+ allowing(mockPasswordMember).isOneToManyAssociation();
+ will(returnValue(false));
+ }
+ });
+
+ employeeWO = wrapperFactory.wrap(employeeDO);
+ }
+
+ /**
+ * Mandatory hook.
+ */
+ protected abstract WrapperFactoryAbstract createWrapperFactory();
+
+ @Test(expected = DisabledException.class)
+ public void shouldNotBeAbleToModifyProperty() {
+
+ // given
+ final DisabledFacet disabledFacet = new DisabledFacetAlwaysEverywhere(mockPasswordMember);
+ facets = Arrays.asList((Facet)disabledFacet, new PropertySetterFacetViaSetterMethod(setPasswordMethod, mockPasswordMember));
+
+ final Consent visibilityConsent = new Allow(new InteractionResult(new PropertyVisibilityEvent(employeeDO, null)));
+
+ final InteractionResult usabilityInteractionResult = new InteractionResult(new PropertyUsabilityEvent(employeeDO, null));
+ usabilityInteractionResult.advise("disabled", disabledFacet);
+ final Consent usabilityConsent = new Veto(usabilityInteractionResult);
+
+ context.checking(new Expectations() {
+ {
+ allowing(mockPasswordMember).getFacets(with(any(Filter.class)));
+ will(returnValue(facets));
+
+ allowing(mockPasswordMember).isVisible(session, mockEmployeeAdapter, Where.ANYWHERE);
+ will(returnValue(visibilityConsent));
+
+ allowing(mockPasswordMember).isUsable(session, mockEmployeeAdapter, Where.ANYWHERE);
+ will(returnValue(usabilityConsent));
+ }
+ });
+
+ // when
+ employeeWO.setPassword(passwordValue);
+
+ // then should throw exception
+ }
+
+ @Test
+ public void canModifyProperty() {
+ // given
+
+ final Consent visibilityConsent = new Allow(new InteractionResult(new PropertyVisibilityEvent(employeeDO, mockPasswordIdentifier)));
+ final Consent usabilityConsent = new Allow(new InteractionResult(new PropertyUsabilityEvent(employeeDO, mockPasswordIdentifier)));
+ final Consent validityConsent = new Allow(new InteractionResult(new PropertyModifyEvent(employeeDO, mockPasswordIdentifier, passwordValue)));
+
+ context.checking(new Expectations() {
+ {
+ allowing(mockPasswordMember).isVisible(session, mockEmployeeAdapter, Where.ANYWHERE);
+ will(returnValue(visibilityConsent));
+
+ allowing(mockPasswordMember).isUsable(session, mockEmployeeAdapter, Where.ANYWHERE);
+ will(returnValue(usabilityConsent));
+
+ allowing(mockPasswordMember).isAssociationValid(mockEmployeeAdapter, mockPasswordAdapter);
+ will(returnValue(validityConsent));
+ }
+ });
+
+ facets = Arrays.asList((Facet)new PropertySetterFacetViaSetterMethod(setPasswordMethod, mockPasswordMember));
+ context.checking(new Expectations() {
+ {
+ oneOf(mockPasswordMember).getFacets(with(any(Filter.class)));
+ will(returnValue(facets));
+
+ oneOf(mockPasswordMember).set(mockEmployeeAdapter, mockPasswordAdapter);
+ }
+ });
+
+ // when
+ employeeWO.setPassword(passwordValue);
+
+
+ // and given
+ facets = Arrays.asList((Facet)new PropertyAccessorFacetViaAccessor(getPasswordMethod, mockPasswordMember));
+ context.checking(new Expectations() {
+ {
+ oneOf(mockPasswordMember).getFacets(with(any(Filter.class)));
+ will(returnValue(facets));
+
+ oneOf(mockPasswordMember).get(mockEmployeeAdapter);
+ will(returnValue(mockPasswordAdapter));
+ }
+ });
+
+ // then be allowed
+ assertThat(employeeWO.getPassword(), is(passwordValue));
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryCglibTest_wrappedObject.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryCglibTest_wrappedObject.java b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryCglibTest_wrappedObject.java
new file mode 100644
index 0000000..b867968
--- /dev/null
+++ b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryCglibTest_wrappedObject.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.progmodel.wrapper;
+
+import org.apache.isis.core.wrapper.WrapperFactoryAbstract;
+import org.apache.isis.core.wrapper.WrapperFactoryCglib;
+
+public class WrapperFactoryCglibTest_wrappedObject extends WrapperFactoryAbstractTest_wrappedObject {
+
+ @Override
+ protected WrapperFactoryAbstract createWrapperFactory() {
+ return new WrapperFactoryCglib();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryCglibTest_wrappedObject_transient.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryCglibTest_wrappedObject_transient.java b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryCglibTest_wrappedObject_transient.java
new file mode 100644
index 0000000..e45a9d5
--- /dev/null
+++ b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryCglibTest_wrappedObject_transient.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.progmodel.wrapper;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.jmock.Expectations;
+import org.jmock.auto.Mock;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.events.PropertyModifyEvent;
+import org.apache.isis.applib.events.PropertyUsabilityEvent;
+import org.apache.isis.applib.events.PropertyVisibilityEvent;
+import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.applib.services.wrapper.DisabledException;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.consent.Allow;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.InteractionResult;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
+import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet;
+import org.apache.isis.core.progmodel.facets.members.disabled.staticmethod.DisabledFacetAlwaysEverywhere;
+import org.apache.isis.core.progmodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor;
+import org.apache.isis.core.progmodel.facets.properties.modify.PropertySetterFacetViaSetterMethod;
+import org.apache.isis.core.runtime.authentication.standard.SimpleSession;
+import org.apache.isis.core.tck.dom.claimapp.employees.Employee;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.apache.isis.core.wrapper.WrapperFactoryAbstract;
+import org.apache.isis.core.wrapper.WrapperFactoryCglib;
+import org.apache.isis.core.wrapper.WrapperFactoryDefault;
+
+public class WrapperFactoryCglibTest_wrappedObject_transient extends WrapperFactoryAbstractTest_wrappedObject_transient {
+
+ @Override
+ protected WrapperFactoryAbstract createWrapperFactory() {
+ return new WrapperFactoryCglib();
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryJavassistTest_wrappedObject.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryJavassistTest_wrappedObject.java b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryJavassistTest_wrappedObject.java
new file mode 100644
index 0000000..b7ce494
--- /dev/null
+++ b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryJavassistTest_wrappedObject.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.progmodel.wrapper;
+
+import org.apache.isis.core.wrapper.WrapperFactoryAbstract;
+import org.apache.isis.core.wrapper.WrapperFactoryJavassist;
+
+public class WrapperFactoryJavassistTest_wrappedObject extends WrapperFactoryAbstractTest_wrappedObject {
+
+ @Override
+ protected WrapperFactoryAbstract createWrapperFactory() {
+ return new WrapperFactoryJavassist();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryJavassistTest_wrappedObject_transient.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryJavassistTest_wrappedObject_transient.java b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryJavassistTest_wrappedObject_transient.java
new file mode 100644
index 0000000..c613348
--- /dev/null
+++ b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrapperFactoryJavassistTest_wrappedObject_transient.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.progmodel.wrapper;
+
+import org.apache.isis.core.wrapper.WrapperFactoryAbstract;
+import org.apache.isis.core.wrapper.WrapperFactoryJavassist;
+
+public class WrapperFactoryJavassistTest_wrappedObject_transient extends WrapperFactoryAbstractTest_wrappedObject_transient {
+
+ @Override
+ protected WrapperFactoryAbstract createWrapperFactory() {
+ return new WrapperFactoryJavassist();
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
index b38d41f..6e7aecb 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
@@ -171,6 +171,13 @@ public class ToDoItem implements Comparable<ToDoItem> {
public void setDescription(final String description) {
this.description = description;
}
+ public void modifyDescription(final String description) {
+ setDescription(description);
+ }
+ public void clearDescription() {
+ setDescription(null);
+ }
+
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_description.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_description.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_description.java
index 5dadac7..11e5ae3 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_description.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_description.java
@@ -74,6 +74,37 @@ public class ToDoItemTest_description extends ToDoIntegTest {
}
@Test
+ public void cannotUseModify() throws Exception {
+
+ expectedExceptions.expectMessage("Cannot invoke supporting method for 'Description'; use only property accessor/mutator");
+
+ // given
+ assertThat(toDoItem.getDescription(), is("Buy bread"));
+
+ // when
+ toDoItem.modifyDescription("Buy bread and butter");
+
+ // then
+ assertThat(toDoItem.getDescription(), is("Buy bread"));
+ }
+
+ @Test
+ public void cannotUseClear() throws Exception {
+
+ expectedExceptions.expectMessage("Cannot invoke supporting method for 'Description'; use only property accessor/mutator");
+
+ // given
+ assertThat(toDoItem.getDescription(), is("Buy bread"));
+
+ // when
+ toDoItem.clearDescription();
+
+ // then
+ assertThat(toDoItem.getDescription(), is("Buy bread"));
+ }
+
+
+ @Test
public void onlyJustShortEnough() throws Exception {
// when, then
[3/4] ISIS-772: reimplemented.
Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
new file mode 100644
index 0000000..93b6d6b
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
@@ -0,0 +1,679 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.handlers;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.events.CollectionAccessEvent;
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.applib.events.ObjectTitleEvent;
+import org.apache.isis.applib.events.PropertyAccessEvent;
+import org.apache.isis.applib.events.UsabilityEvent;
+import org.apache.isis.applib.events.ValidityEvent;
+import org.apache.isis.applib.events.VisibilityEvent;
+import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.applib.services.wrapper.DisabledException;
+import org.apache.isis.applib.services.wrapper.HiddenException;
+import org.apache.isis.applib.services.wrapper.InteractionException;
+import org.apache.isis.applib.services.wrapper.InvalidException;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.WrapperObject;
+import org.apache.isis.applib.services.wrapper.WrapperFactory.ExecutionMode;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.adapter.util.AdapterUtils;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod;
+import org.apache.isis.core.metamodel.consent.InteractionResult;
+import org.apache.isis.core.metamodel.facetapi.DecoratingFacet;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facets.ImperativeFacet;
+import org.apache.isis.core.metamodel.facets.accessor.PropertyOrCollectionAccessorFacet;
+import org.apache.isis.core.metamodel.facets.actions.choices.ActionChoicesFacet;
+import org.apache.isis.core.metamodel.facets.actions.defaults.ActionDefaultsFacet;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionRemoveFromFacet;
+import org.apache.isis.core.metamodel.facets.param.choices.ActionParameterChoicesFacet;
+import org.apache.isis.core.metamodel.facets.properties.choices.PropertyChoicesFacet;
+import org.apache.isis.core.metamodel.facets.properties.defaults.PropertyDefaultFacet;
+import org.apache.isis.core.metamodel.facets.properties.modify.PropertyInitializationFacet;
+import org.apache.isis.core.metamodel.facets.properties.modify.PropertySetterFacet;
+import org.apache.isis.core.metamodel.interactions.ObjectTitleContext;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
+import org.apache.isis.core.progmodel.facets.actions.validate.method.ActionValidationFacetViaMethod;
+import org.apache.isis.core.progmodel.facets.collections.validate.CollectionValidateAddToFacetViaMethod;
+import org.apache.isis.core.progmodel.facets.collections.validate.CollectionValidateRemoveFromFacetViaMethod;
+import org.apache.isis.core.progmodel.facets.members.disabled.method.DisableForContextFacetViaMethod;
+import org.apache.isis.core.progmodel.facets.members.hidden.method.HideForContextFacetViaMethod;
+import org.apache.isis.core.progmodel.facets.properties.modify.PropertyClearFacetViaClearMethod;
+import org.apache.isis.core.progmodel.facets.properties.modify.PropertySetterFacetViaModifyMethod;
+import org.apache.isis.core.progmodel.facets.properties.validate.PropertyValidateFacetViaMethod;
+
+public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandlerDefault<T> {
+
+ private final Map<Method, Collection<?>> collectionViewObjectsByMethod = new HashMap<Method, Collection<?>>();
+ private final Map<Method, Map<?, ?>> mapViewObjectsByMethod = new HashMap<Method, Map<?, ?>>();
+
+ private final AuthenticationSessionProvider authenticationSessionProvider;
+ private final SpecificationLoader specificationLookup;
+ private final AdapterManager adapterManager;
+ private final ObjectPersistor objectPersistor;
+
+ private final ProxyContextHandler proxy;
+
+ /**
+ * The <tt>title()</tt> method; may be <tt>null</tt>.
+ */
+ protected Method titleMethod;
+
+ /**
+ * The <tt>save()</tt> method from {@link WrapperObject#save()}.
+ */
+ protected Method saveMethod;
+
+ /**
+ * The <tt>underlying()</tt> method from {@link WrapperObject#wrapped()}.
+ */
+ protected Method wrappedMethod;
+
+ public DomainObjectInvocationHandler(final T delegate, final WrapperFactory embeddedViewer, final ExecutionMode mode, final AuthenticationSessionProvider authenticationSessionProvider, final SpecificationLoader specificationLookup, final AdapterManager adapterManager,
+ final ObjectPersistor objectPersistor, ProxyContextHandler proxy) {
+ super(delegate, embeddedViewer, mode);
+
+ this.proxy = proxy;
+ this.authenticationSessionProvider = authenticationSessionProvider;
+ this.specificationLookup = specificationLookup;
+ this.adapterManager = adapterManager;
+ this.objectPersistor = objectPersistor;
+
+ try {
+ titleMethod = delegate.getClass().getMethod("title", new Class[] {});
+ saveMethod = WrapperObject.class.getMethod("save", new Class[] {});
+ wrappedMethod = WrapperObject.class.getMethod("wrapped", new Class[] {});
+ } catch (final NoSuchMethodException e) {
+ }
+ }
+
+ @Override
+ public Object invoke(final Object proxyObject, final Method method, final Object[] args) throws Throwable {
+
+ if (isObjectMethod(method)) {
+ return delegate(method, args);
+ }
+
+ // workaround for JDO-enhanced..
+ if(isJdoMethod(method)) {
+ return delegate(method, args);
+ }
+
+ if(isInjectMethod(method)) {
+ return delegate(method, args);
+ }
+
+ final ObjectAdapter targetAdapter = getAdapterManager().getAdapterFor(getDelegate());
+
+ if (isTitleMethod(method)) {
+ return handleTitleMethod(method, args, targetAdapter);
+ }
+
+
+
+ final ObjectSpecification targetNoSpec = targetAdapter.getSpecification();
+
+ // save method, through the proxy
+ if (isSaveMethod(method)) {
+ return handleSaveMethod(getAuthenticationSession(), targetAdapter, targetNoSpec);
+ }
+
+ if (isUnderlyingMethod(method)) {
+ return getDelegate();
+ }
+
+ final ObjectMember objectMember = locateAndCheckMember(method);
+ final List<Facet> imperativeFacets = getImperativeFacets(objectMember, method);
+
+ final String memberName = objectMember.getName();
+
+ if (instanceOf(imperativeFacets, DisableForContextFacetViaMethod.class, HideForContextFacetViaMethod.class)) {
+ throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'", memberName));
+ }
+
+ final String methodName = method.getName();
+
+ if (instanceOf(imperativeFacets, ActionDefaultsFacet.class, PropertyDefaultFacet.class, ActionChoicesFacet.class, ActionParameterChoicesFacet.class, PropertyChoicesFacet.class)) {
+ return method.invoke(getDelegate(), args);
+ }
+
+ // for all members, check visibility and usability
+ checkVisibility(getAuthenticationSession(), targetAdapter, objectMember);
+
+ if (objectMember.isOneToOneAssociation()) {
+
+ if (instanceOf(imperativeFacets, PropertyValidateFacetViaMethod.class, PropertySetterFacetViaModifyMethod.class, PropertyClearFacetViaClearMethod.class)) {
+ throw new UnsupportedOperationException(String.format("Cannot invoke supporting method for '%s'; use only property accessor/mutator", memberName));
+ }
+
+ final OneToOneAssociation otoa = (OneToOneAssociation) objectMember;
+ if (instanceOf(imperativeFacets, PropertyOrCollectionAccessorFacet.class)) {
+ return handleGetterMethodOnProperty(args, targetAdapter, otoa, methodName);
+ }
+ if (instanceOf(imperativeFacets, PropertySetterFacet.class, PropertyInitializationFacet.class)) {
+ checkUsability(getAuthenticationSession(), targetAdapter, objectMember);
+ return handleSetterMethodOnProperty(args, getAuthenticationSession(), targetAdapter, otoa, methodName);
+ }
+ }
+ if (objectMember.isOneToManyAssociation()) {
+
+ if (instanceOf(imperativeFacets, CollectionValidateAddToFacetViaMethod.class, CollectionValidateRemoveFromFacetViaMethod.class)) {
+ throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'; use only collection accessor/mutator", memberName));
+ }
+
+ final OneToManyAssociation otma = (OneToManyAssociation) objectMember;
+ if (instanceOf(imperativeFacets, PropertyOrCollectionAccessorFacet.class)) {
+ return handleGetterMethodOnCollection(method, args, targetAdapter, otma, memberName);
+ }
+ if (instanceOf(imperativeFacets, CollectionAddToFacet.class)) {
+ checkUsability(getAuthenticationSession(), targetAdapter, objectMember);
+ return handleCollectionAddToMethod(args, targetAdapter, otma, methodName);
+ }
+ if (instanceOf(imperativeFacets, CollectionRemoveFromFacet.class)) {
+ checkUsability(getAuthenticationSession(), targetAdapter, objectMember);
+ return handleCollectionRemoveFromMethod(args, targetAdapter, otma, methodName);
+ }
+ }
+
+ // filter out
+ if (instanceOf(imperativeFacets, PropertyOrCollectionAccessorFacet.class)) {
+ throw new UnsupportedOperationException(String.format("Can only invoke accessor on properties or collections; '%s' represents %s", methodName, decode(objectMember)));
+ }
+ if (instanceOf(imperativeFacets, PropertySetterFacet.class)) {
+ throw new UnsupportedOperationException(String.format("Can only invoke mutator on properties; '%s' represents %s", methodName, decode(objectMember)));
+ }
+ if (instanceOf(imperativeFacets, CollectionAddToFacet.class)) {
+ throw new UnsupportedOperationException(String.format("Can only invoke 'adder' on collections; '%s' represents %s", methodName, decode(objectMember)));
+ }
+ if (instanceOf(imperativeFacets, CollectionRemoveFromFacet.class)) {
+ throw new UnsupportedOperationException(String.format("Can only invoke 'remover' on collections; '%s' represents %s", methodName, decode(objectMember)));
+ }
+
+ if (objectMember instanceof ObjectAction) {
+
+ if (instanceOf(imperativeFacets, ActionValidationFacetViaMethod.class)) {
+ throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'; use only the 'invoke' method", memberName));
+ }
+
+ checkUsability(getAuthenticationSession(), targetAdapter, objectMember);
+
+ final ObjectAction noa = (ObjectAction) objectMember;
+ return handleActionMethod(args, getAuthenticationSession(), targetAdapter, noa, memberName);
+ }
+
+ throw new UnsupportedOperationException(String.format("Unknown member type '%s'", objectMember));
+ }
+
+ private boolean isJdoMethod(final Method method) {
+ return methodStartsWith(method, "jdo");
+ }
+
+ private boolean isInjectMethod(final Method method) {
+ return methodStartsWith(method, "inject");
+ }
+
+ private boolean methodStartsWith(final Method method, final String prefix) {
+ return method.getName().startsWith(prefix);
+ }
+
+ public List<Facet> getImperativeFacets(final ObjectMember objectMember, final Method method) {
+ final List<Facet> imperativeFacets = objectMember.getFacets(new Filter<Facet>() {
+ @Override
+ public boolean accept(final Facet facet) {
+ final ImperativeFacet imperativeFacet = asImperativeFacet(facet);
+ if (imperativeFacet == null) {
+ return false;
+ }
+ return imperativeFacet.getMethods().contains(method);
+ }
+
+ private ImperativeFacet asImperativeFacet(final Facet facet) {
+ if (facet == null) {
+ return null;
+ }
+ if (facet instanceof ImperativeFacet) {
+ return (ImperativeFacet) facet;
+ }
+ Facet underlyingFacet = facet.getUnderlyingFacet();
+ return asImperativeFacet(underlyingFacet);
+ }
+ });
+
+ // there will be at least one
+ if (imperativeFacets.isEmpty()) {
+ throw new IllegalStateException("should be at least one imperative facet");
+ }
+ return imperativeFacets;
+ }
+
+ private static boolean instanceOf(final List<?> objects, final Class<?>... superTypes) {
+ for (final Class<?> superType : superTypes) {
+ for (Object obj : objects) {
+ // handle the *WrapTransaction facets etc
+ if(obj instanceof DecoratingFacet) {
+ DecoratingFacet<?> decoratingFacet = (DecoratingFacet<?>) obj;
+ obj = ((DecoratingFacet<?>) obj).getDecoratedFacet();
+ }
+ if (superType.isAssignableFrom(obj.getClass())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // title
+ // /////////////////////////////////////////////////////////////////
+
+ private Object handleTitleMethod(final Method method, final Object[] args, final ObjectAdapter targetAdapter) throws IllegalAccessException, InvocationTargetException {
+
+ resolveIfRequired(targetAdapter);
+
+ final ObjectSpecification targetNoSpec = targetAdapter.getSpecification();
+ final ObjectTitleContext titleContext = targetNoSpec.createTitleInteractionContext(getAuthenticationSession(), InteractionInvocationMethod.BY_USER, targetAdapter);
+ final ObjectTitleEvent titleEvent = titleContext.createInteractionEvent();
+ notifyListeners(titleEvent);
+ return titleEvent.getTitle();
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // save
+ // /////////////////////////////////////////////////////////////////
+
+ private Object handleSaveMethod(final AuthenticationSession session, final ObjectAdapter targetAdapter, final ObjectSpecification targetNoSpec) {
+
+ final InteractionResult interactionResult = targetNoSpec.isValidResult(targetAdapter);
+ notifyListenersAndVetoIfRequired(interactionResult);
+
+ if (getExecutionMode() == ExecutionMode.EXECUTE) {
+ if (targetAdapter.isTransient()) {
+ getObjectPersistor().makePersistent(targetAdapter);
+ }
+ }
+ return null;
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // property - access
+ // /////////////////////////////////////////////////////////////////
+
+ private Object handleGetterMethodOnProperty(final Object[] args, final ObjectAdapter targetAdapter, final OneToOneAssociation otoa, final String methodName) {
+ if (args.length != 0) {
+ throw new IllegalArgumentException("Invoking a 'get' should have no arguments");
+ }
+
+ resolveIfRequired(targetAdapter);
+
+ final ObjectAdapter currentReferencedAdapter = otoa.get(targetAdapter);
+ final Object currentReferencedObj = AdapterUtils.unwrap(currentReferencedAdapter);
+
+ final PropertyAccessEvent ev = new PropertyAccessEvent(getDelegate(), otoa.getIdentifier(), currentReferencedObj);
+ notifyListeners(ev);
+ return currentReferencedObj;
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // property - modify
+ // /////////////////////////////////////////////////////////////////
+
+ private Object handleSetterMethodOnProperty(final Object[] args, final AuthenticationSession session, final ObjectAdapter targetAdapter, final OneToOneAssociation otoa, final String methodName) {
+ if (args.length != 1) {
+ throw new IllegalArgumentException("Invoking a setter should only have a single argument");
+ }
+
+ resolveIfRequired(targetAdapter);
+
+ final Object argumentObj = underlying(args[0]);
+ final ObjectAdapter argumentAdapter = argumentObj != null ? getAdapterManager().adapterFor(argumentObj) : null;
+
+ final InteractionResult interactionResult = otoa.isAssociationValid(targetAdapter, argumentAdapter).getInteractionResult();
+ notifyListenersAndVetoIfRequired(interactionResult);
+
+ if (getExecutionMode() == ExecutionMode.EXECUTE) {
+ otoa.set(targetAdapter, argumentAdapter);
+ }
+
+ objectChangedIfRequired(targetAdapter);
+
+ return null;
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // collection - access
+ // /////////////////////////////////////////////////////////////////
+
+ private Object handleGetterMethodOnCollection(final Method method, final Object[] args, final ObjectAdapter targetAdapter, final OneToManyAssociation otma, final String memberName) {
+ if (args.length != 0) {
+ throw new IllegalArgumentException("Invoking a 'get' should have no arguments");
+ }
+
+ resolveIfRequired(targetAdapter);
+
+ final ObjectAdapter currentReferencedAdapter = otma.get(targetAdapter);
+ final Object currentReferencedObj = AdapterUtils.unwrap(currentReferencedAdapter);
+
+ final CollectionAccessEvent ev = new CollectionAccessEvent(getDelegate(), otma.getIdentifier());
+
+ if (currentReferencedObj instanceof Collection) {
+ final Collection<?> collectionViewObject = lookupViewObject(method, memberName, (Collection<?>) currentReferencedObj, otma);
+ notifyListeners(ev);
+ return collectionViewObject;
+ } else if (currentReferencedObj instanceof Map) {
+ final Map<?, ?> mapViewObject = lookupViewObject(method, memberName, (Map<?, ?>) currentReferencedObj, otma);
+ notifyListeners(ev);
+ return mapViewObject;
+ }
+ throw new IllegalArgumentException(String.format("Collection type '%s' not supported by framework", currentReferencedObj.getClass().getName()));
+ }
+
+ /**
+ * Looks up (or creates) a proxy for this object.
+ */
+ private Collection<?> lookupViewObject(final Method method, final String memberName, final Collection<?> collectionToLookup, final OneToManyAssociation otma) {
+ Collection<?> collectionViewObject = collectionViewObjectsByMethod.get(method);
+ if (collectionViewObject == null) {
+ if (collectionToLookup instanceof WrapperObject) {
+ collectionViewObject = collectionToLookup;
+ } else {
+ collectionViewObject = proxy.proxy(collectionToLookup, memberName, this, otma);
+ }
+ collectionViewObjectsByMethod.put(method, collectionViewObject);
+ }
+ return collectionViewObject;
+ }
+
+ private Map<?, ?> lookupViewObject(final Method method, final String memberName, final Map<?, ?> mapToLookup, final OneToManyAssociation otma) {
+ Map<?, ?> mapViewObject = mapViewObjectsByMethod.get(method);
+ if (mapViewObject == null) {
+ if (mapToLookup instanceof WrapperObject) {
+ mapViewObject = mapToLookup;
+ } else {
+ mapViewObject = proxy.proxy(mapToLookup, memberName, this, otma);
+ }
+ mapViewObjectsByMethod.put(method, mapViewObject);
+ }
+ return mapViewObject;
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // collection - add to
+ // /////////////////////////////////////////////////////////////////
+
+ private Object handleCollectionAddToMethod(final Object[] args, final ObjectAdapter targetAdapter, final OneToManyAssociation otma, final String methodName) {
+
+ if (args.length != 1) {
+ throw new IllegalArgumentException("Invoking a addTo should only have a single argument");
+ }
+
+ resolveIfRequired(targetAdapter);
+
+ final Object argumentObj = underlying(args[0]);
+ if (argumentObj == null) {
+ throw new IllegalArgumentException("Must provide a non-null object to add");
+ }
+ final ObjectAdapter argumentNO = getAdapterManager().adapterFor(argumentObj);
+
+ final InteractionResult interactionResult = otma.isValidToAdd(targetAdapter, argumentNO).getInteractionResult();
+ notifyListenersAndVetoIfRequired(interactionResult);
+
+ if (getExecutionMode() == ExecutionMode.EXECUTE) {
+ otma.addElement(targetAdapter, argumentNO);
+ }
+
+ objectChangedIfRequired(targetAdapter);
+
+ return null;
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // collection - remove from
+ // /////////////////////////////////////////////////////////////////
+
+ private Object handleCollectionRemoveFromMethod(final Object[] args, final ObjectAdapter targetAdapter, final OneToManyAssociation otma, final String methodName) {
+ if (args.length != 1) {
+ throw new IllegalArgumentException("Invoking a removeFrom should only have a single argument");
+ }
+
+ resolveIfRequired(targetAdapter);
+
+ final Object argumentObj = underlying(args[0]);
+ if (argumentObj == null) {
+ throw new IllegalArgumentException("Must provide a non-null object to remove");
+ }
+ final ObjectAdapter argumentAdapter = getAdapterManager().adapterFor(argumentObj);
+
+ final InteractionResult interactionResult = otma.isValidToRemove(targetAdapter, argumentAdapter).getInteractionResult();
+ notifyListenersAndVetoIfRequired(interactionResult);
+
+ if (getExecutionMode() == ExecutionMode.EXECUTE) {
+ otma.removeElement(targetAdapter, argumentAdapter);
+ }
+
+ objectChangedIfRequired(targetAdapter);
+
+ return null;
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // action
+ // /////////////////////////////////////////////////////////////////
+
+ private Object handleActionMethod(final Object[] args, final AuthenticationSession session, final ObjectAdapter targetAdapter, final ObjectAction noa, final String memberName) {
+
+ final Object[] underlyingArgs = new Object[args.length];
+ int i = 0;
+ for (final Object arg : args) {
+ underlyingArgs[i++] = underlying(arg);
+ }
+
+ final ObjectAdapter[] argAdapters = new ObjectAdapter[underlyingArgs.length];
+ int j = 0;
+ for (final Object underlyingArg : underlyingArgs) {
+ argAdapters[j++] = underlyingArg != null ? getAdapterManager().adapterFor(underlyingArg) : null;
+ }
+
+ final InteractionResult interactionResult = noa.isProposedArgumentSetValid(targetAdapter, argAdapters).getInteractionResult();
+ notifyListenersAndVetoIfRequired(interactionResult);
+
+ if (getExecutionMode() == ExecutionMode.EXECUTE) {
+ final ObjectAdapter actionReturnNO = noa.execute(targetAdapter, argAdapters);
+ return AdapterUtils.unwrap(actionReturnNO);
+ }
+
+ objectChangedIfRequired(targetAdapter);
+
+ return null;
+ }
+
+ private Object underlying(final Object arg) {
+ if (arg instanceof WrapperObject) {
+ final WrapperObject argViewObject = (WrapperObject) arg;
+ return argViewObject.wrapped();
+ } else {
+ return arg;
+ }
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // visibility and usability checks (common to all members)
+ // /////////////////////////////////////////////////////////////////
+
+ /**
+ * REVIEW: ideally should provide some way to allow to caller to indicate the 'where' context. Having
+ * a hard-coded value like this is an approximation.
+ */
+ private final Where where = Where.ANYWHERE;
+
+ private void checkVisibility(final AuthenticationSession session, final ObjectAdapter targetObjectAdapter, final ObjectMember objectMember) {
+ final Consent visibleConsent = objectMember.isVisible(getAuthenticationSession(), targetObjectAdapter, where);
+ final InteractionResult interactionResult = visibleConsent.getInteractionResult();
+ notifyListenersAndVetoIfRequired(interactionResult);
+ }
+
+ private void checkUsability(final AuthenticationSession session, final ObjectAdapter targetObjectAdapter, final ObjectMember objectMember) {
+ final InteractionResult interactionResult = objectMember.isUsable(getAuthenticationSession(), targetObjectAdapter, where).getInteractionResult();
+ notifyListenersAndVetoIfRequired(interactionResult);
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // notify listeners
+ // /////////////////////////////////////////////////////////////////
+
+ private void notifyListenersAndVetoIfRequired(final InteractionResult interactionResult) {
+ final InteractionEvent interactionEvent = interactionResult.getInteractionEvent();
+ notifyListeners(interactionEvent);
+ if (interactionEvent.isVeto()) {
+ throw toException(interactionEvent);
+ }
+ }
+
+ private String decode(final ObjectMember objectMember) {
+ if (objectMember instanceof OneToOneAssociation) {
+ return "a property";
+ }
+ if (objectMember instanceof OneToManyAssociation) {
+ return "a collection";
+ }
+ if (objectMember instanceof ObjectAction) {
+ return "an action";
+ }
+ return "an UNKNOWN member type";
+ }
+
+ /**
+ * Wraps a {@link InteractionEvent#isVeto() vetoing}
+ * {@link InteractionEvent} in a corresponding {@link InteractionException},
+ * and returns it.
+ */
+ private InteractionException toException(final InteractionEvent interactionEvent) {
+ if (!interactionEvent.isVeto()) {
+ throw new IllegalArgumentException("Provided interactionEvent must be a veto");
+ }
+ if (interactionEvent instanceof ValidityEvent) {
+ final ValidityEvent validityEvent = (ValidityEvent) interactionEvent;
+ return new InvalidException(validityEvent);
+ }
+ if (interactionEvent instanceof VisibilityEvent) {
+ final VisibilityEvent visibilityEvent = (VisibilityEvent) interactionEvent;
+ return new HiddenException(visibilityEvent);
+ }
+ if (interactionEvent instanceof UsabilityEvent) {
+ final UsabilityEvent usabilityEvent = (UsabilityEvent) interactionEvent;
+ return new DisabledException(usabilityEvent);
+ }
+ throw new IllegalArgumentException("Provided interactionEvent must be a VisibilityEvent, UsabilityEvent or a ValidityEvent");
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // switching
+ // /////////////////////////////////////////////////////////////////
+
+ private ObjectMember locateAndCheckMember(final Method method) {
+ final ObjectSpecificationDefault objectSpecificationDefault = getJavaSpecificationOfOwningClass(method);
+ final ObjectMember member = objectSpecificationDefault.getMember(method);
+
+ if (member == null) {
+ final String methodName = method.getName();
+ throw new UnsupportedOperationException("Method '" + methodName + "' being invoked does not correspond to any of the object's fields or actions.");
+ }
+ return member;
+ }
+
+ protected boolean isTitleMethod(final Method method) {
+ return method.equals(titleMethod);
+ }
+
+ protected boolean isSaveMethod(final Method method) {
+ return method.equals(saveMethod);
+ }
+
+ protected boolean isUnderlyingMethod(final Method method) {
+ return method.equals(wrappedMethod);
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // Specification lookup
+ // /////////////////////////////////////////////////////////////////
+
+ private ObjectSpecificationDefault getJavaSpecificationOfOwningClass(final Method method) {
+ return getJavaSpecification(method.getDeclaringClass());
+ }
+
+ private ObjectSpecificationDefault getJavaSpecification(final Class<?> clazz) {
+ final ObjectSpecification nos = getSpecification(clazz);
+ if (!(nos instanceof ObjectSpecificationDefault)) {
+ throw new UnsupportedOperationException("Only Java is supported (specification is '" + nos.getClass().getCanonicalName() + "')");
+ }
+ return (ObjectSpecificationDefault) nos;
+ }
+
+ private ObjectSpecification getSpecification(final Class<?> type) {
+ final ObjectSpecification nos = getSpecificationLookup().loadSpecification(type);
+ return nos;
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // Dependencies
+ // /////////////////////////////////////////////////////////////////
+
+ protected SpecificationLoader getSpecificationLookup() {
+ return specificationLookup;
+ }
+
+ public AuthenticationSessionProvider getAuthenticationSessionProvider() {
+ return authenticationSessionProvider;
+ }
+
+ protected AuthenticationSession getAuthenticationSession() {
+ return getAuthenticationSessionProvider().getAuthenticationSession();
+ }
+
+ protected AdapterManager getAdapterManager() {
+ return adapterManager;
+ }
+
+ protected ObjectPersistor getObjectPersistor() {
+ return objectPersistor;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/MapInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/MapInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/MapInvocationHandler.java
new file mode 100644
index 0000000..ed6cbc1
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/MapInvocationHandler.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.handlers;
+
+import java.util.Map;
+
+import org.apache.isis.core.commons.lang.ObjectExtensions;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+
+class MapInvocationHandler<T, C> extends AbstractCollectionInvocationHandler<T, C> {
+
+ public MapInvocationHandler(final C collectionToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
+ super(collectionToProxy, collectionName, handler, otma);
+
+ try {
+ intercept(ObjectExtensions.getMethod(collectionToProxy, "containsKey", Object.class));
+ intercept(ObjectExtensions.getMethod(collectionToProxy, "containsValue", Object.class));
+ intercept(ObjectExtensions.getMethod(collectionToProxy, "size"));
+ intercept(ObjectExtensions.getMethod(collectionToProxy, "isEmpty"));
+ veto(ObjectExtensions.getMethod(collectionToProxy, "put", Object.class, Object.class));
+ veto(ObjectExtensions.getMethod(collectionToProxy, "remove", Object.class));
+ veto(ObjectExtensions.getMethod(collectionToProxy, "putAll", Map.class));
+ veto(ObjectExtensions.getMethod(collectionToProxy, "clear"));
+ } catch (final NoSuchMethodException e) {
+ // ///CLOVER:OFF
+ throw new RuntimeException("A Collection method could not be found: " + e.getMessage());
+ // ///CLOVER:ON
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/ProxyContextHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/ProxyContextHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/ProxyContextHandler.java
new file mode 100644
index 0000000..5f942bc
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/ProxyContextHandler.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.handlers;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.WrapperFactory.ExecutionMode;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
+import org.apache.isis.core.commons.ensure.Ensure;
+import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.wrapper.proxy.ProxyInstantiator;
+
+public class ProxyContextHandler {
+
+ private final ProxyInstantiator proxyInstantiator;
+
+ public ProxyContextHandler(final ProxyInstantiator proxyInstantiator) {
+ this.proxyInstantiator = proxyInstantiator;
+ }
+
+ public <T> T proxy(final T domainObject, final WrapperFactory wrapperFactory, final ExecutionMode mode, final AuthenticationSessionProvider authenticationSessionProvider, final SpecificationLoader specificationLookup, final AdapterManager adapterManager, final ObjectPersistor objectPersistor) {
+
+ Ensure.ensureThatArg(wrapperFactory, is(not(nullValue())));
+ Ensure.ensureThatArg(authenticationSessionProvider, is(not(nullValue())));
+ Ensure.ensureThatArg(specificationLookup, is(not(nullValue())));
+ Ensure.ensureThatArg(adapterManager, is(not(nullValue())));
+ Ensure.ensureThatArg(objectPersistor, is(not(nullValue())));
+
+ final DomainObjectInvocationHandler<T> invocationHandler = new DomainObjectInvocationHandler<T>(domainObject, wrapperFactory, mode, authenticationSessionProvider, specificationLookup, adapterManager, objectPersistor, this);
+
+ return proxyInstantiator.instantiateProxy(invocationHandler);
+ }
+
+ /**
+ * Whether to execute or not will be picked up from the supplied parent
+ * handler.
+ */
+ public <T, E> Collection<E> proxy(final Collection<E> collectionToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
+
+ final CollectionInvocationHandler<T, Collection<E>> collectionInvocationHandler = new CollectionInvocationHandler<T, Collection<E>>(collectionToProxy, collectionName, handler, otma);
+ collectionInvocationHandler.setResolveObjectChangedEnabled(handler.isResolveObjectChangedEnabled());
+
+ return proxyInstantiator.instantiateProxy(collectionInvocationHandler);
+ }
+
+ /**
+ * Whether to execute or not will be picked up from the supplied parent
+ * handler.
+ */
+ public <T, P, Q> Map<P, Q> proxy(final Map<P, Q> collectionToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
+
+ final MapInvocationHandler<T, Map<P, Q>> mapInvocationHandler = new MapInvocationHandler<T, Map<P, Q>>(collectionToProxy, collectionName, handler, otma);
+ mapInvocationHandler.setResolveObjectChangedEnabled(handler.isResolveObjectChangedEnabled());
+
+ return proxyInstantiator.instantiateProxy(mapInvocationHandler);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/AbstractCollectionInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/AbstractCollectionInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/AbstractCollectionInvocationHandler.java
deleted file mode 100644
index e5581d4..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/AbstractCollectionInvocationHandler.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.isis.applib.events.CollectionMethodEvent;
-import org.apache.isis.applib.events.InteractionEvent;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
-
-abstract class AbstractCollectionInvocationHandler<T, C> extends DelegatingInvocationHandlerDefault<C> {
-
- private final List<Method> interceptedMethods = new ArrayList<Method>();
- private final List<Method> vetoedMethods = new ArrayList<Method>();
- private final String collectionName;
- private final OneToManyAssociation oneToManyAssociation;
- private final T domainObject;
-
- public AbstractCollectionInvocationHandler(final C collectionOrMapToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
- super(collectionOrMapToProxy, handler.getHeadlessViewer(), handler.getExecutionMode());
- this.collectionName = collectionName;
- this.oneToManyAssociation = otma;
- this.domainObject = handler.getDelegate();
- }
-
- protected Method intercept(final Method method) {
- this.interceptedMethods.add(method);
- return method;
- }
-
- protected Method veto(final Method method) {
- this.vetoedMethods.add(method);
- return method;
- }
-
- public String getCollectionName() {
- return collectionName;
- }
-
- public OneToManyAssociation getCollection() {
- return oneToManyAssociation;
- }
-
- public T getDomainObject() {
- return domainObject;
- }
-
- @Override
- public Object invoke(final Object collectionObject, final Method method, final Object[] args) throws Throwable {
-
- // delegate
- final Object returnValueObj = delegate(method, args);
-
- if (interceptedMethods.contains(method)) {
-
- resolveIfRequired(domainObject);
-
- final InteractionEvent ev = new CollectionMethodEvent(getDelegate(), getCollection().getIdentifier(), getDomainObject(), method.getName(), args, returnValueObj);
- notifyListeners(ev);
- return returnValueObj;
- }
-
- if (vetoedMethods.contains(method)) {
- throw new UnsupportedOperationException(String.format("Method '%s' may not be called directly.", method.getName()));
- }
-
- return returnValueObj;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CgLibClassProxyFactory.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CgLibClassProxyFactory.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CgLibClassProxyFactory.java
deleted file mode 100644
index 8fb2b66..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CgLibClassProxyFactory.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.lang.reflect.InvocationHandler;
-
-import net.sf.cglib.proxy.Callback;
-import net.sf.cglib.proxy.Enhancer;
-import net.sf.cglib.proxy.Factory;
-import net.sf.cglib.proxy.MethodInterceptor;
-
-import org.apache.isis.applib.services.wrapper.WrapperObject;
-
-/**
- * Factory generating a mock for a class.
- * <p>
- * Note that this class is stateful
- */
-public class CgLibClassProxyFactory<T> implements IProxyFactory<T> {
-
- @Override
- @SuppressWarnings("unchecked")
- public T createProxy(final T toProxy, final InvocationHandler handler) {
- final Class<T> proxyClass = (Class<T>) toProxy.getClass();
- return createProxy(proxyClass, handler);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public T createProxy(final Class<T> toProxyClass, final InvocationHandler handler) {
-
- final MethodInterceptor interceptor = new InvocationHandlerMethodInterceptor(handler);
-
- // Create the proxy
- final Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(toProxyClass);
- enhancer.setInterfaces(new Class[] { WrapperObject.class });
- enhancer.setCallbackType(interceptor.getClass());
-
- final Class<?> enhancedClass = enhancer.createClass();
-
- Enhancer.registerCallbacks(enhancedClass, new Callback[] { interceptor });
-
- Factory factory;
- try {
- factory = (Factory) ClassInstantiatorFactoryCE.getInstantiator().newInstance(enhancedClass);
- } catch (final InstantiationException e) {
- throw new RuntimeException("Fail to instantiate mock for " + toProxyClass + " on " + ClassInstantiatorFactoryCE.getJVM() + " JVM");
- }
-
- return (T) factory;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CgLibProxy.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CgLibProxy.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CgLibProxy.java
deleted file mode 100644
index ec432cc..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CgLibProxy.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import net.sf.cglib.proxy.Enhancer;
-import net.sf.cglib.proxy.Factory;
-
-import org.apache.isis.applib.services.wrapper.WrapperObject;
-import org.apache.isis.core.metamodel.specloader.classsubstitutor.CglibEnhanced;
-
-public class CgLibProxy<T> {
-
- private final DelegatingInvocationHandler<T> handler;
-
- public CgLibProxy(final DelegatingInvocationHandler<T> handler) {
- this.handler = handler;
- }
-
- @SuppressWarnings("unchecked")
- public T proxy() {
-
- final T toProxy = handler.getDelegate();
-
- // handle if already proxied using cglib.
- if (CglibEnhanced.class.isAssignableFrom(toProxy.getClass())) {
-
- handler.setResolveObjectChangedEnabled(true);
-
- final Class<? extends Object> enhancedClass = toProxy.getClass();
- final Class<? extends Object> origSuperclass = toProxy.getClass().getSuperclass();
-
- final List<Class> interfaces = new ArrayList<Class>();
- interfaces.addAll(Arrays.asList(enhancedClass.getInterfaces()));
- interfaces.remove(Factory.class); // if there.
- interfaces.add(WrapperObject.class);
-
- InvocationHandlerMethodInterceptor interceptor = new InvocationHandlerMethodInterceptor(handler);
- return (T) Enhancer.create(origSuperclass, interfaces.toArray(new Class[] {}), interceptor);
- }
-
- final Class<T> clazz = (Class<T>) toProxy.getClass();
-
- T proxy = null;
- try {
- final IProxyFactory<T> proxyFactory = clazz.isInterface() ? new JavaProxyFactory<T>() : new CgLibClassProxyFactory<T>();
- proxy = proxyFactory.createProxy(clazz, handler);
- } catch (final RuntimeExceptionWrapper e) {
- throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
- }
- return proxy;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/ClassInstantiatorFactoryCE.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/ClassInstantiatorFactoryCE.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/ClassInstantiatorFactoryCE.java
deleted file mode 100644
index 465daf2..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/ClassInstantiatorFactoryCE.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-/**
- * Factory returning a {@link IClassInstantiatorCE}for the current JVM
- */
-class ClassInstantiatorFactoryCE {
-
- private static IClassInstantiatorCE instantiator = new ObjenesisClassInstantiatorCE();
-
- // ///CLOVER:OFF
- private ClassInstantiatorFactoryCE() {
- }
-
- // ///CLOVER:ON
-
- /**
- * Returns the current JVM as specified in the Systtem properties
- *
- * @return current JVM
- */
- public static String getJVM() {
- return System.getProperty("java.vm.vendor");
- }
-
- /**
- * Returns the current JVM specification version (1.5, 1.4, 1.3)
- *
- * @return current JVM specification version
- */
- public static String getJVMSpecificationVersion() {
- return System.getProperty("java.specification.version");
- }
-
- public static boolean is1_3Specifications() {
- return getJVMSpecificationVersion().equals("1.3");
- }
-
- /**
- * Returns a class instantiator suitable for the current JVM
- *
- * @return a class instantiator usable on the current JVM
- */
- public static IClassInstantiatorCE getInstantiator() {
- return instantiator;
- }
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CollectionInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CollectionInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CollectionInvocationHandler.java
deleted file mode 100644
index 8c4e245..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/CollectionInvocationHandler.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.isis.core.commons.lang.ObjectExtensions;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
-
-class CollectionInvocationHandler<T, R> extends AbstractCollectionInvocationHandler<T, R> {
-
- public CollectionInvocationHandler(final R collectionToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
- super(collectionToProxy, collectionName, handler, otma);
-
- try {
- intercept(ObjectExtensions.getMethod(collectionToProxy, "contains", Object.class));
- intercept(ObjectExtensions.getMethod(collectionToProxy, "size"));
- intercept(ObjectExtensions.getMethod(collectionToProxy, "isEmpty"));
- if (collectionToProxy instanceof List) {
- intercept(ObjectExtensions.getMethod(collectionToProxy, "get", int.class));
- }
- veto(ObjectExtensions.getMethod(collectionToProxy, "add", Object.class));
- veto(ObjectExtensions.getMethod(collectionToProxy, "remove", Object.class));
- veto(ObjectExtensions.getMethod(collectionToProxy, "addAll", Collection.class));
- veto(ObjectExtensions.getMethod(collectionToProxy, "removeAll", Collection.class));
- veto(ObjectExtensions.getMethod(collectionToProxy, "retainAll", Collection.class));
- veto(ObjectExtensions.getMethod(collectionToProxy, "clear"));
- } catch (final NoSuchMethodException e) {
- // ///CLOVER:OFF
- throw new RuntimeException("A Collection method could not be found: " + e.getMessage());
- // ///CLOVER:ON
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DelegatingInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DelegatingInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DelegatingInvocationHandler.java
deleted file mode 100644
index 44b3204..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DelegatingInvocationHandler.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.lang.reflect.InvocationHandler;
-
-public interface DelegatingInvocationHandler<T> extends InvocationHandler {
-
- T getDelegate();
-
- public boolean isResolveObjectChangedEnabled();
-
- public void setResolveObjectChangedEnabled(boolean resolveObjectChangedEnabled);
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DelegatingInvocationHandlerDefault.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DelegatingInvocationHandlerDefault.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DelegatingInvocationHandlerDefault.java
deleted file mode 100644
index 337853e..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DelegatingInvocationHandlerDefault.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import org.apache.isis.applib.events.InteractionEvent;
-import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.applib.services.wrapper.WrapperFactory.ExecutionMode;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.runtime.persistence.container.DomainObjectContainerObjectChanged;
-import org.apache.isis.core.runtime.persistence.container.DomainObjectContainerResolve;
-
-public class DelegatingInvocationHandlerDefault<T> implements DelegatingInvocationHandler<T> {
-
- private final T delegate;
- protected final WrapperFactory wrapperFactory;
- private final ExecutionMode executionMode;
-
- protected final Method equalsMethod;
- protected final Method hashCodeMethod;
- protected final Method toStringMethod;
-
- private final DomainObjectContainerObjectChanged domainObjectContainerObjectChanged;
- private final DomainObjectContainerResolve domainObjectContainerResolve;
-
- private boolean resolveObjectChangedEnabled;
-
- public DelegatingInvocationHandlerDefault(final T delegate, final WrapperFactory headlessViewer, final ExecutionMode executionMode) {
- if (delegate == null) {
- throw new IllegalArgumentException("delegate must not be null");
- }
- this.delegate = delegate;
- this.wrapperFactory = headlessViewer;
- this.executionMode = executionMode;
-
- this.domainObjectContainerResolve = new DomainObjectContainerResolve();
- this.domainObjectContainerObjectChanged = new DomainObjectContainerObjectChanged();
-
- try {
- equalsMethod = delegate.getClass().getMethod("equals", new Class[] { Object.class });
- hashCodeMethod = delegate.getClass().getMethod("hashCode", new Class[] {});
- toStringMethod = delegate.getClass().getMethod("toString", new Class[] {});
- } catch (final NoSuchMethodException e) {
- // ///CLOVER:OFF
- throw new RuntimeException("An Object method could not be found: " + e.getMessage());
- // ///CLOVER:ON
- }
- }
-
- @Override
- public boolean isResolveObjectChangedEnabled() {
- return resolveObjectChangedEnabled;
- }
-
- @Override
- public void setResolveObjectChangedEnabled(final boolean resolveObjectChangedEnabled) {
- this.resolveObjectChangedEnabled = resolveObjectChangedEnabled;
- }
-
- protected void resolveIfRequired(final ObjectAdapter targetAdapter) {
- resolveIfRequired(targetAdapter.getObject());
- }
-
- protected void resolveIfRequired(final Object domainObject) {
- if (resolveObjectChangedEnabled) {
- domainObjectContainerResolve.resolve(domainObject);
- }
- }
-
- protected void objectChangedIfRequired(final ObjectAdapter targetAdapter) {
- objectChangedIfRequired(targetAdapter.getObject());
- }
-
- protected void objectChangedIfRequired(final Object domainObject) {
- if (resolveObjectChangedEnabled) {
- domainObjectContainerObjectChanged.objectChanged(domainObject);
- }
- }
-
- public WrapperFactory getHeadlessViewer() {
- return wrapperFactory;
- }
-
- @Override
- public T getDelegate() {
- return delegate;
- }
-
- public ExecutionMode getExecutionMode() {
- return executionMode;
- }
-
- protected Object delegate(final Method method, final Object[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
-
- return method.invoke(getDelegate(), args);
- }
-
- protected boolean isObjectMethod(final Method method) {
- return toStringMethod.equals(method) || hashCodeMethod.equals(method) || equalsMethod.equals(method);
- }
-
- @Override
- public Object invoke(final Object object, final Method method, final Object[] args) throws Throwable {
- return method.invoke(object, args);
- }
-
- protected InteractionEvent notifyListeners(final InteractionEvent interactionEvent) {
- wrapperFactory.notifyListeners(interactionEvent);
- return interactionEvent;
- }
-
-}
[4/4] git commit: ISIS-772: reimplemented.
Posted by da...@apache.org.
ISIS-772: reimplemented.
... so that WrapperFactoryDefault now uses javassist. WrapperFactoryCglib is the original impl. To use, explicitly include cglib-nodep and asm in pom.xml (they are now marked as optional).
In addition:
- new tests in todo app to demonstrate some of the usage of this
- fixed an error that the use of 'modify' in wrapped methods was not being disallowed
- resurrected previously-@Ignore'd unit tests for wrapper factory.
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/074d2c4e
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/074d2c4e
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/074d2c4e
Branch: refs/heads/master
Commit: 074d2c4e45f90e27e903ab0823c109eacbdefe71
Parents: 72a1911
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri May 2 18:22:19 2014 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri May 2 18:22:19 2014 +0100
----------------------------------------------------------------------
core/unittestsupport/pom.xml | 1 -
.../jmocking/JavassistImposteriser.java | 14 +-
core/wrapper/pom.xml | 31 +-
.../core/wrapper/WrapperFactoryAbstract.java | 315 +++++++++
.../isis/core/wrapper/WrapperFactoryCglib.java | 30 +
.../core/wrapper/WrapperFactoryDefault.java | 269 +-------
.../core/wrapper/WrapperFactoryJavassist.java | 30 +
.../dispatchers/InteractionEventDispatcher.java | 28 +
.../InteractionEventDispatcherTypeSafe.java | 34 +
.../AbstractCollectionInvocationHandler.java | 89 +++
.../handlers/CollectionInvocationHandler.java | 53 ++
.../handlers/DelegatingInvocationHandler.java | 32 +
.../DelegatingInvocationHandlerDefault.java | 131 ++++
.../handlers/DomainObjectInvocationHandler.java | 679 +++++++++++++++++++
.../wrapper/handlers/MapInvocationHandler.java | 48 ++
.../wrapper/handlers/ProxyContextHandler.java | 84 +++
.../AbstractCollectionInvocationHandler.java | 89 ---
.../internal/CgLibClassProxyFactory.java | 71 --
.../isis/core/wrapper/internal/CgLibProxy.java | 74 --
.../internal/ClassInstantiatorFactoryCE.java | 65 --
.../internal/CollectionInvocationHandler.java | 53 --
.../internal/DelegatingInvocationHandler.java | 32 -
.../DelegatingInvocationHandlerDefault.java | 131 ----
.../internal/DomainObjectInvocationHandler.java | 669 ------------------
.../wrapper/internal/IClassInstantiatorCE.java | 37 -
.../core/wrapper/internal/IProxyFactory.java | 28 -
.../internal/InteractionEventDispatcher.java | 28 -
.../InteractionEventDispatcherTypeSafe.java | 34 -
.../InvocationHandlerMethodInterceptor.java | 39 --
.../core/wrapper/internal/JavaProxyFactory.java | 40 --
.../wrapper/internal/MapInvocationHandler.java | 48 --
.../internal/ObjenesisClassInstantiatorCE.java | 31 -
.../isis/core/wrapper/internal/Proxy.java | 80 ---
.../internal/RuntimeExceptionWrapper.java | 33 -
.../isis/core/wrapper/internal/util/Util.java | 53 ++
.../core/wrapper/proxy/ProxyInstantiator.java | 26 +
.../proxy/ProxyInstantiatorForCglib.java | 101 +++
.../proxy/ProxyInstantiatorForJavassist.java | 77 +++
...WrappedFactoryDefaultTest_wrappedObject.java | 153 -----
...toryDefaultTest_wrappedObject_transient.java | 251 -------
...rapperFactoryAbstractTest_wrappedObject.java | 380 +++++++++++
...oryAbstractTest_wrappedObject_transient.java | 257 +++++++
.../WrapperFactoryCglibTest_wrappedObject.java | 32 +
...actoryCglibTest_wrappedObject_transient.java | 73 ++
...apperFactoryJavassistTest_wrappedObject.java | 32 +
...ryJavassistTest_wrappedObject_transient.java | 31 +
.../dom/src/main/java/dom/todo/ToDoItem.java | 7 +
.../tests/props/ToDoItemTest_description.java | 31 +
48 files changed, 2678 insertions(+), 2276 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/unittestsupport/pom.xml
----------------------------------------------------------------------
diff --git a/core/unittestsupport/pom.xml b/core/unittestsupport/pom.xml
index fe0fc1c..fe70990 100644
--- a/core/unittestsupport/pom.xml
+++ b/core/unittestsupport/pom.xml
@@ -97,7 +97,6 @@
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
- <!--<version>3.18.1-GA</version>-->
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/jmocking/JavassistImposteriser.java
----------------------------------------------------------------------
diff --git a/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/jmocking/JavassistImposteriser.java b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/jmocking/JavassistImposteriser.java
index 0fc9332..df56eb5 100644
--- a/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/jmocking/JavassistImposteriser.java
+++ b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/jmocking/JavassistImposteriser.java
@@ -97,8 +97,7 @@ public class JavassistImposteriser implements Imposteriser {
private Class<?> proxyClass(Class<?> mockedType, Class<?>... ancilliaryTypes) {
- final ProxyFactory proxyFactory;
- proxyFactory = new ProxyFactory();
+ final ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setFilter(new MethodFilter() {
@Override
public boolean isHandled(final Method m) {
@@ -107,13 +106,8 @@ public class JavassistImposteriser implements Imposteriser {
}
});
- if(mockedType.isInterface()) {
- proxyFactory.setSuperclass(Object.class);
- proxyFactory.setInterfaces(prepend(mockedType, ancilliaryTypes));
- } else {
- proxyFactory.setSuperclass(mockedType);
- proxyFactory.setInterfaces(ancilliaryTypes);
- }
+ proxyFactory.setSuperclass(mockedType);
+ proxyFactory.setInterfaces(ancilliaryTypes);
return proxyFactory.createClass();
@@ -197,7 +191,7 @@ public class JavassistImposteriser implements Imposteriser {
// return proxy;
}
- private Class<?>[] prepend(Class<?> first, Class<?>... rest) {
+ private static Class<?>[] combine(Class<?> first, Class<?>... rest) {
Class<?>[] all = new Class<?>[rest.length+1];
all[0] = first;
System.arraycopy(rest, 0, all, 1, rest.length);
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/pom.xml
----------------------------------------------------------------------
diff --git a/core/wrapper/pom.xml b/core/wrapper/pom.xml
index 9836543..ee90ddf 100644
--- a/core/wrapper/pom.xml
+++ b/core/wrapper/pom.xml
@@ -109,20 +109,29 @@
<scope>test</scope>
</dependency>
- <dependency>
+ <dependency>
+ <groupId>org.objenesis</groupId>
+ <artifactId>objenesis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.javassist</groupId>
+ <artifactId>javassist</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.objenesis</groupId>
- <artifactId>objenesis</artifactId>
- </dependency>
+ <!-- explicitly include for use of WrapperFactoryCglib -->
+ <optional>true</optional>
+ </dependency>
- <dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib-nodep</artifactId>
- </dependency>
+ <dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib-nodep</artifactId>
+ <!-- explicitly include for use of WrapperFactoryCglib -->
+ <optional>true</optional>
+ </dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryAbstract.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryAbstract.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryAbstract.java
new file mode 100644
index 0000000..88c33c8
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryAbstract.java
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.events.ActionArgumentEvent;
+import org.apache.isis.applib.events.ActionInvocationEvent;
+import org.apache.isis.applib.events.ActionUsabilityEvent;
+import org.apache.isis.applib.events.ActionVisibilityEvent;
+import org.apache.isis.applib.events.CollectionAccessEvent;
+import org.apache.isis.applib.events.CollectionAddToEvent;
+import org.apache.isis.applib.events.CollectionMethodEvent;
+import org.apache.isis.applib.events.CollectionRemoveFromEvent;
+import org.apache.isis.applib.events.CollectionUsabilityEvent;
+import org.apache.isis.applib.events.CollectionVisibilityEvent;
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.applib.events.ObjectTitleEvent;
+import org.apache.isis.applib.events.ObjectValidityEvent;
+import org.apache.isis.applib.events.PropertyAccessEvent;
+import org.apache.isis.applib.events.PropertyModifyEvent;
+import org.apache.isis.applib.events.PropertyUsabilityEvent;
+import org.apache.isis.applib.events.PropertyVisibilityEvent;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.WrapperObject;
+import org.apache.isis.applib.services.wrapper.listeners.InteractionListener;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProviderAware;
+import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
+import org.apache.isis.core.metamodel.adapter.ObjectPersistorAware;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManagerAware;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderAware;
+import org.apache.isis.core.wrapper.dispatchers.InteractionEventDispatcher;
+import org.apache.isis.core.wrapper.dispatchers.InteractionEventDispatcherTypeSafe;
+import org.apache.isis.core.wrapper.handlers.ProxyContextHandler;
+import org.apache.isis.core.wrapper.proxy.ProxyInstantiator;
+
+public abstract class WrapperFactoryAbstract implements WrapperFactory, AuthenticationSessionProviderAware, SpecificationLoaderAware, AdapterManagerAware, ObjectPersistorAware {
+
+ private final List<InteractionListener> listeners = new ArrayList<InteractionListener>();
+ private final Map<Class<? extends InteractionEvent>, InteractionEventDispatcher> dispatchersByEventClass = new HashMap<Class<? extends InteractionEvent>, InteractionEventDispatcher>();
+
+ private AuthenticationSessionProvider authenticationSessionProvider;
+ private SpecificationLoader specificationLookup;
+ private AdapterManager adapterManager;
+ private ObjectPersistor objectPersistor;
+
+ private final ProxyContextHandler proxy;
+
+ public WrapperFactoryAbstract(final ProxyInstantiator proxyInstantiator) {
+
+ proxy = new ProxyContextHandler(proxyInstantiator);
+
+ dispatchersByEventClass.put(ObjectTitleEvent.class, new InteractionEventDispatcherTypeSafe<ObjectTitleEvent>() {
+ @Override
+ public void dispatchTypeSafe(final ObjectTitleEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.objectTitleRead(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(PropertyVisibilityEvent.class, new InteractionEventDispatcherTypeSafe<PropertyVisibilityEvent>() {
+ @Override
+ public void dispatchTypeSafe(final PropertyVisibilityEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.propertyVisible(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(PropertyUsabilityEvent.class, new InteractionEventDispatcherTypeSafe<PropertyUsabilityEvent>() {
+ @Override
+ public void dispatchTypeSafe(final PropertyUsabilityEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.propertyUsable(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(PropertyAccessEvent.class, new InteractionEventDispatcherTypeSafe<PropertyAccessEvent>() {
+ @Override
+ public void dispatchTypeSafe(final PropertyAccessEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.propertyAccessed(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(PropertyModifyEvent.class, new InteractionEventDispatcherTypeSafe<PropertyModifyEvent>() {
+ @Override
+ public void dispatchTypeSafe(final PropertyModifyEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.propertyModified(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(CollectionVisibilityEvent.class, new InteractionEventDispatcherTypeSafe<CollectionVisibilityEvent>() {
+ @Override
+ public void dispatchTypeSafe(final CollectionVisibilityEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.collectionVisible(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(CollectionUsabilityEvent.class, new InteractionEventDispatcherTypeSafe<CollectionUsabilityEvent>() {
+ @Override
+ public void dispatchTypeSafe(final CollectionUsabilityEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.collectionUsable(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(CollectionAccessEvent.class, new InteractionEventDispatcherTypeSafe<CollectionAccessEvent>() {
+ @Override
+ public void dispatchTypeSafe(final CollectionAccessEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.collectionAccessed(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(CollectionAddToEvent.class, new InteractionEventDispatcherTypeSafe<CollectionAddToEvent>() {
+ @Override
+ public void dispatchTypeSafe(final CollectionAddToEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.collectionAddedTo(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(CollectionRemoveFromEvent.class, new InteractionEventDispatcherTypeSafe<CollectionRemoveFromEvent>() {
+ @Override
+ public void dispatchTypeSafe(final CollectionRemoveFromEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.collectionRemovedFrom(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(ActionVisibilityEvent.class, new InteractionEventDispatcherTypeSafe<ActionVisibilityEvent>() {
+ @Override
+ public void dispatchTypeSafe(final ActionVisibilityEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.actionVisible(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(ActionUsabilityEvent.class, new InteractionEventDispatcherTypeSafe<ActionUsabilityEvent>() {
+ @Override
+ public void dispatchTypeSafe(final ActionUsabilityEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.actionUsable(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(ActionArgumentEvent.class, new InteractionEventDispatcherTypeSafe<ActionArgumentEvent>() {
+ @Override
+ public void dispatchTypeSafe(final ActionArgumentEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.actionArgument(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(ActionInvocationEvent.class, new InteractionEventDispatcherTypeSafe<ActionInvocationEvent>() {
+ @Override
+ public void dispatchTypeSafe(final ActionInvocationEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.actionInvoked(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(ObjectValidityEvent.class, new InteractionEventDispatcherTypeSafe<ObjectValidityEvent>() {
+ @Override
+ public void dispatchTypeSafe(final ObjectValidityEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.objectPersisted(interactionEvent);
+ }
+ }
+ });
+ dispatchersByEventClass.put(CollectionMethodEvent.class, new InteractionEventDispatcherTypeSafe<CollectionMethodEvent>() {
+ @Override
+ public void dispatchTypeSafe(final CollectionMethodEvent interactionEvent) {
+ for (final InteractionListener l : getListeners()) {
+ l.collectionMethodInvoked(interactionEvent);
+ }
+ }
+ });
+ }
+
+ // /////////////////////////////////////////////////////////////
+ // wrap and unwrap
+ // /////////////////////////////////////////////////////////////
+
+ @Override
+ public <T> T wrap(final T domainObject) {
+ return wrap(domainObject, ExecutionMode.EXECUTE);
+ }
+
+ @Override
+ public <T> T wrap(final T domainObject, final ExecutionMode mode) {
+ if (isWrapper(domainObject)) {
+ return domainObject;
+ }
+ return createProxy(domainObject, mode);
+ }
+
+ protected <T> T createProxy(final T domainObject, final ExecutionMode mode) {
+ return proxy.proxy(domainObject, this, mode, getAuthenticationSessionProvider(), getSpecificationLookup(), getAdapterManager(), getObjectPersistor());
+ }
+
+ @Override
+ public boolean isWrapper(final Object possibleWrappedDomainObject) {
+ return possibleWrappedDomainObject instanceof WrapperObject;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ @Programmatic
+ public <T> T unwrap(T possibleWrappedDomainObject) {
+ if(isWrapper(possibleWrappedDomainObject)) {
+ WrapperObject wrapperObject = (WrapperObject) possibleWrappedDomainObject;
+ return (T) wrapperObject.wrapped();
+ }
+ return possibleWrappedDomainObject;
+ }
+
+ // /////////////////////////////////////////////////////////////
+ // Listeners
+ // /////////////////////////////////////////////////////////////
+
+ @Override
+ public List<InteractionListener> getListeners() {
+ return listeners;
+ }
+
+ @Override
+ public boolean addInteractionListener(final InteractionListener listener) {
+ return listeners.add(listener);
+ }
+
+ @Override
+ public boolean removeInteractionListener(final InteractionListener listener) {
+ return listeners.remove(listener);
+ }
+
+ @Override
+ public void notifyListeners(final InteractionEvent interactionEvent) {
+ final InteractionEventDispatcher dispatcher = dispatchersByEventClass.get(interactionEvent.getClass());
+ if (dispatcher == null) {
+ throw new RuntimeException("Unknown InteractionEvent - register into dispatchers map");
+ }
+ dispatcher.dispatch(interactionEvent);
+ }
+
+ // /////////////////////////////////////////////////////////////
+ // Listeners
+ // /////////////////////////////////////////////////////////////
+
+ protected AuthenticationSessionProvider getAuthenticationSessionProvider() {
+ return authenticationSessionProvider;
+ }
+ @Programmatic
+ @Override
+ public void setAuthenticationSessionProvider(final AuthenticationSessionProvider authenticationSessionProvider) {
+ this.authenticationSessionProvider = authenticationSessionProvider;
+ }
+
+ protected AdapterManager getAdapterManager() {
+ return adapterManager;
+ }
+ @Programmatic
+ @Override
+ public void setAdapterManager(final AdapterManager adapterManager) {
+ this.adapterManager = adapterManager;
+ }
+
+
+ protected SpecificationLoader getSpecificationLookup() {
+ return specificationLookup;
+ }
+ @Programmatic
+ @Override
+ public void setSpecificationLookup(final SpecificationLoader specificationLookup) {
+ this.specificationLookup = specificationLookup;
+ }
+
+ protected ObjectPersistor getObjectPersistor() {
+ return objectPersistor;
+ }
+ @Programmatic
+ @Override
+ public void setObjectPersistor(final ObjectPersistor objectPersistor) {
+ this.objectPersistor = objectPersistor;
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryCglib.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryCglib.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryCglib.java
new file mode 100644
index 0000000..fd75b59
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryCglib.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper;
+
+import org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForCglib;
+
+public class WrapperFactoryCglib extends WrapperFactoryAbstract {
+
+ public WrapperFactoryCglib() {
+ super(new ProxyInstantiatorForCglib());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryDefault.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryDefault.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryDefault.java
index 1e89bc2..62bc688 100644
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryDefault.java
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryDefault.java
@@ -19,274 +19,7 @@
package org.apache.isis.core.wrapper;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.events.ActionArgumentEvent;
-import org.apache.isis.applib.events.ActionInvocationEvent;
-import org.apache.isis.applib.events.ActionUsabilityEvent;
-import org.apache.isis.applib.events.ActionVisibilityEvent;
-import org.apache.isis.applib.events.CollectionAccessEvent;
-import org.apache.isis.applib.events.CollectionAddToEvent;
-import org.apache.isis.applib.events.CollectionMethodEvent;
-import org.apache.isis.applib.events.CollectionRemoveFromEvent;
-import org.apache.isis.applib.events.CollectionUsabilityEvent;
-import org.apache.isis.applib.events.CollectionVisibilityEvent;
-import org.apache.isis.applib.events.InteractionEvent;
-import org.apache.isis.applib.events.ObjectTitleEvent;
-import org.apache.isis.applib.events.ObjectValidityEvent;
-import org.apache.isis.applib.events.PropertyAccessEvent;
-import org.apache.isis.applib.events.PropertyModifyEvent;
-import org.apache.isis.applib.events.PropertyUsabilityEvent;
-import org.apache.isis.applib.events.PropertyVisibilityEvent;
-import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.applib.services.wrapper.WrapperObject;
-import org.apache.isis.applib.services.wrapper.listeners.InteractionListener;
-import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
-import org.apache.isis.core.commons.authentication.AuthenticationSessionProviderAware;
-import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
-import org.apache.isis.core.metamodel.adapter.ObjectPersistorAware;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManagerAware;
-import org.apache.isis.core.metamodel.spec.SpecificationLoader;
-import org.apache.isis.core.metamodel.spec.SpecificationLoaderAware;
-import org.apache.isis.core.wrapper.internal.InteractionEventDispatcher;
-import org.apache.isis.core.wrapper.internal.InteractionEventDispatcherTypeSafe;
-import org.apache.isis.core.wrapper.internal.Proxy;
-
-public class WrapperFactoryDefault implements WrapperFactory, AuthenticationSessionProviderAware, SpecificationLoaderAware, AdapterManagerAware, ObjectPersistorAware {
-
- private final List<InteractionListener> listeners = new ArrayList<InteractionListener>();
- private final Map<Class<? extends InteractionEvent>, InteractionEventDispatcher> dispatchersByEventClass = new HashMap<Class<? extends InteractionEvent>, InteractionEventDispatcher>();
-
- private AuthenticationSessionProvider authenticationSessionProvider;
- private SpecificationLoader specificationLookup;
- private AdapterManager adapterManager;
- private ObjectPersistor objectPersistor;
-
- public WrapperFactoryDefault() {
- dispatchersByEventClass.put(ObjectTitleEvent.class, new InteractionEventDispatcherTypeSafe<ObjectTitleEvent>() {
- @Override
- public void dispatchTypeSafe(final ObjectTitleEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.objectTitleRead(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(PropertyVisibilityEvent.class, new InteractionEventDispatcherTypeSafe<PropertyVisibilityEvent>() {
- @Override
- public void dispatchTypeSafe(final PropertyVisibilityEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.propertyVisible(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(PropertyUsabilityEvent.class, new InteractionEventDispatcherTypeSafe<PropertyUsabilityEvent>() {
- @Override
- public void dispatchTypeSafe(final PropertyUsabilityEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.propertyUsable(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(PropertyAccessEvent.class, new InteractionEventDispatcherTypeSafe<PropertyAccessEvent>() {
- @Override
- public void dispatchTypeSafe(final PropertyAccessEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.propertyAccessed(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(PropertyModifyEvent.class, new InteractionEventDispatcherTypeSafe<PropertyModifyEvent>() {
- @Override
- public void dispatchTypeSafe(final PropertyModifyEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.propertyModified(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(CollectionVisibilityEvent.class, new InteractionEventDispatcherTypeSafe<CollectionVisibilityEvent>() {
- @Override
- public void dispatchTypeSafe(final CollectionVisibilityEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.collectionVisible(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(CollectionUsabilityEvent.class, new InteractionEventDispatcherTypeSafe<CollectionUsabilityEvent>() {
- @Override
- public void dispatchTypeSafe(final CollectionUsabilityEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.collectionUsable(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(CollectionAccessEvent.class, new InteractionEventDispatcherTypeSafe<CollectionAccessEvent>() {
- @Override
- public void dispatchTypeSafe(final CollectionAccessEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.collectionAccessed(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(CollectionAddToEvent.class, new InteractionEventDispatcherTypeSafe<CollectionAddToEvent>() {
- @Override
- public void dispatchTypeSafe(final CollectionAddToEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.collectionAddedTo(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(CollectionRemoveFromEvent.class, new InteractionEventDispatcherTypeSafe<CollectionRemoveFromEvent>() {
- @Override
- public void dispatchTypeSafe(final CollectionRemoveFromEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.collectionRemovedFrom(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(ActionVisibilityEvent.class, new InteractionEventDispatcherTypeSafe<ActionVisibilityEvent>() {
- @Override
- public void dispatchTypeSafe(final ActionVisibilityEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.actionVisible(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(ActionUsabilityEvent.class, new InteractionEventDispatcherTypeSafe<ActionUsabilityEvent>() {
- @Override
- public void dispatchTypeSafe(final ActionUsabilityEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.actionUsable(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(ActionArgumentEvent.class, new InteractionEventDispatcherTypeSafe<ActionArgumentEvent>() {
- @Override
- public void dispatchTypeSafe(final ActionArgumentEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.actionArgument(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(ActionInvocationEvent.class, new InteractionEventDispatcherTypeSafe<ActionInvocationEvent>() {
- @Override
- public void dispatchTypeSafe(final ActionInvocationEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.actionInvoked(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(ObjectValidityEvent.class, new InteractionEventDispatcherTypeSafe<ObjectValidityEvent>() {
- @Override
- public void dispatchTypeSafe(final ObjectValidityEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.objectPersisted(interactionEvent);
- }
- }
- });
- dispatchersByEventClass.put(CollectionMethodEvent.class, new InteractionEventDispatcherTypeSafe<CollectionMethodEvent>() {
- @Override
- public void dispatchTypeSafe(final CollectionMethodEvent interactionEvent) {
- for (final InteractionListener l : getListeners()) {
- l.collectionMethodInvoked(interactionEvent);
- }
- }
- });
- }
-
- // /////////////////////////////////////////////////////////////
- // wrap and unwrap
- // /////////////////////////////////////////////////////////////
-
- @Override
- public <T> T wrap(final T domainObject) {
- return wrap(domainObject, ExecutionMode.EXECUTE);
- }
-
- @Override
- public <T> T wrap(final T domainObject, final ExecutionMode mode) {
- if (isWrapper(domainObject)) {
- return domainObject;
- }
- return Proxy.proxy(domainObject, this, mode, authenticationSessionProvider, specificationLookup, adapterManager, objectPersistor);
- }
-
- @Override
- public boolean isWrapper(final Object possibleWrappedDomainObject) {
- return possibleWrappedDomainObject instanceof WrapperObject;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- @Programmatic
- public <T> T unwrap(T possibleWrappedDomainObject) {
- if(isWrapper(possibleWrappedDomainObject)) {
- WrapperObject wrapperObject = (WrapperObject) possibleWrappedDomainObject;
- return (T) wrapperObject.wrapped();
- }
- return possibleWrappedDomainObject;
- }
-
- // /////////////////////////////////////////////////////////////
- // Listeners
- // /////////////////////////////////////////////////////////////
-
- @Override
- public List<InteractionListener> getListeners() {
- return listeners;
- }
-
- @Override
- public boolean addInteractionListener(final InteractionListener listener) {
- return listeners.add(listener);
- }
-
- @Override
- public boolean removeInteractionListener(final InteractionListener listener) {
- return listeners.remove(listener);
- }
-
- @Override
- public void notifyListeners(final InteractionEvent interactionEvent) {
- final InteractionEventDispatcher dispatcher = dispatchersByEventClass.get(interactionEvent.getClass());
- if (dispatcher == null) {
- throw new RuntimeException("Unknown InteractionEvent - register into dispatchers map");
- }
- dispatcher.dispatch(interactionEvent);
- }
-
- // /////////////////////////////////////////////////////////////
- // Listeners
- // /////////////////////////////////////////////////////////////
-
- @Programmatic
- @Override
- public void setAuthenticationSessionProvider(final AuthenticationSessionProvider authenticationSessionProvider) {
- this.authenticationSessionProvider = authenticationSessionProvider;
- }
-
- @Programmatic
- @Override
- public void setAdapterManager(final AdapterManager adapterManager) {
- this.adapterManager = adapterManager;
- }
-
- @Programmatic
- @Override
- public void setSpecificationLookup(final SpecificationLoader specificationLookup) {
- this.specificationLookup = specificationLookup;
- }
-
- @Programmatic
- @Override
- public void setObjectPersistor(final ObjectPersistor objectPersistor) {
- this.objectPersistor = objectPersistor;
- }
-
+public class WrapperFactoryDefault extends WrapperFactoryJavassist {
}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryJavassist.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryJavassist.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryJavassist.java
new file mode 100644
index 0000000..e71580f
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryJavassist.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper;
+
+import org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist;
+
+public class WrapperFactoryJavassist extends WrapperFactoryAbstract {
+
+ public WrapperFactoryJavassist() {
+ super(new ProxyInstantiatorForJavassist());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/dispatchers/InteractionEventDispatcher.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/dispatchers/InteractionEventDispatcher.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/dispatchers/InteractionEventDispatcher.java
new file mode 100644
index 0000000..2dfa70c
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/dispatchers/InteractionEventDispatcher.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.dispatchers;
+
+import org.apache.isis.applib.events.InteractionEvent;
+
+public interface InteractionEventDispatcher {
+
+ void dispatch(InteractionEvent interactionEvent);
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/dispatchers/InteractionEventDispatcherTypeSafe.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/dispatchers/InteractionEventDispatcherTypeSafe.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/dispatchers/InteractionEventDispatcherTypeSafe.java
new file mode 100644
index 0000000..c568633
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/dispatchers/InteractionEventDispatcherTypeSafe.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.dispatchers;
+
+import org.apache.isis.applib.events.InteractionEvent;
+
+public abstract class InteractionEventDispatcherTypeSafe<T extends InteractionEvent> implements InteractionEventDispatcher {
+
+ public abstract void dispatchTypeSafe(T interactionEvent);
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void dispatch(final InteractionEvent interactionEvent) {
+ dispatchTypeSafe((T) interactionEvent);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/AbstractCollectionInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/AbstractCollectionInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/AbstractCollectionInvocationHandler.java
new file mode 100644
index 0000000..ab1e808
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/AbstractCollectionInvocationHandler.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.handlers;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.isis.applib.events.CollectionMethodEvent;
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+
+abstract class AbstractCollectionInvocationHandler<T, C> extends DelegatingInvocationHandlerDefault<C> {
+
+ private final List<Method> interceptedMethods = new ArrayList<Method>();
+ private final List<Method> vetoedMethods = new ArrayList<Method>();
+ private final String collectionName;
+ private final OneToManyAssociation oneToManyAssociation;
+ private final T domainObject;
+
+ public AbstractCollectionInvocationHandler(final C collectionOrMapToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
+ super(collectionOrMapToProxy, handler.getHeadlessViewer(), handler.getExecutionMode());
+ this.collectionName = collectionName;
+ this.oneToManyAssociation = otma;
+ this.domainObject = handler.getDelegate();
+ }
+
+ protected Method intercept(final Method method) {
+ this.interceptedMethods.add(method);
+ return method;
+ }
+
+ protected Method veto(final Method method) {
+ this.vetoedMethods.add(method);
+ return method;
+ }
+
+ public String getCollectionName() {
+ return collectionName;
+ }
+
+ public OneToManyAssociation getCollection() {
+ return oneToManyAssociation;
+ }
+
+ public T getDomainObject() {
+ return domainObject;
+ }
+
+ @Override
+ public Object invoke(final Object collectionObject, final Method method, final Object[] args) throws Throwable {
+
+ // delegate
+ final Object returnValueObj = delegate(method, args);
+
+ if (interceptedMethods.contains(method)) {
+
+ resolveIfRequired(domainObject);
+
+ final InteractionEvent ev = new CollectionMethodEvent(getDelegate(), getCollection().getIdentifier(), getDomainObject(), method.getName(), args, returnValueObj);
+ notifyListeners(ev);
+ return returnValueObj;
+ }
+
+ if (vetoedMethods.contains(method)) {
+ throw new UnsupportedOperationException(String.format("Method '%s' may not be called directly.", method.getName()));
+ }
+
+ return returnValueObj;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/CollectionInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/CollectionInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/CollectionInvocationHandler.java
new file mode 100644
index 0000000..bcf2973
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/CollectionInvocationHandler.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.handlers;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.isis.core.commons.lang.ObjectExtensions;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+
+class CollectionInvocationHandler<T, R> extends AbstractCollectionInvocationHandler<T, R> {
+
+ public CollectionInvocationHandler(final R collectionToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
+ super(collectionToProxy, collectionName, handler, otma);
+
+ try {
+ intercept(ObjectExtensions.getMethod(collectionToProxy, "contains", Object.class));
+ intercept(ObjectExtensions.getMethod(collectionToProxy, "size"));
+ intercept(ObjectExtensions.getMethod(collectionToProxy, "isEmpty"));
+ if (collectionToProxy instanceof List) {
+ intercept(ObjectExtensions.getMethod(collectionToProxy, "get", int.class));
+ }
+ veto(ObjectExtensions.getMethod(collectionToProxy, "add", Object.class));
+ veto(ObjectExtensions.getMethod(collectionToProxy, "remove", Object.class));
+ veto(ObjectExtensions.getMethod(collectionToProxy, "addAll", Collection.class));
+ veto(ObjectExtensions.getMethod(collectionToProxy, "removeAll", Collection.class));
+ veto(ObjectExtensions.getMethod(collectionToProxy, "retainAll", Collection.class));
+ veto(ObjectExtensions.getMethod(collectionToProxy, "clear"));
+ } catch (final NoSuchMethodException e) {
+ // ///CLOVER:OFF
+ throw new RuntimeException("A Collection method could not be found: " + e.getMessage());
+ // ///CLOVER:ON
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DelegatingInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DelegatingInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DelegatingInvocationHandler.java
new file mode 100644
index 0000000..d424f64
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DelegatingInvocationHandler.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.handlers;
+
+import java.lang.reflect.InvocationHandler;
+
+public interface DelegatingInvocationHandler<T> extends InvocationHandler {
+
+ T getDelegate();
+
+ public boolean isResolveObjectChangedEnabled();
+
+ public void setResolveObjectChangedEnabled(boolean resolveObjectChangedEnabled);
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DelegatingInvocationHandlerDefault.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DelegatingInvocationHandlerDefault.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DelegatingInvocationHandlerDefault.java
new file mode 100644
index 0000000..e1b7cdd
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DelegatingInvocationHandlerDefault.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.handlers;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.WrapperFactory.ExecutionMode;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.runtime.persistence.container.DomainObjectContainerObjectChanged;
+import org.apache.isis.core.runtime.persistence.container.DomainObjectContainerResolve;
+
+public class DelegatingInvocationHandlerDefault<T> implements DelegatingInvocationHandler<T> {
+
+ private final T delegate;
+ protected final WrapperFactory wrapperFactory;
+ private final ExecutionMode executionMode;
+
+ protected final Method equalsMethod;
+ protected final Method hashCodeMethod;
+ protected final Method toStringMethod;
+
+ private final DomainObjectContainerObjectChanged domainObjectContainerObjectChanged;
+ private final DomainObjectContainerResolve domainObjectContainerResolve;
+
+ private boolean resolveObjectChangedEnabled;
+
+ public DelegatingInvocationHandlerDefault(final T delegate, final WrapperFactory headlessViewer, final ExecutionMode executionMode) {
+ if (delegate == null) {
+ throw new IllegalArgumentException("delegate must not be null");
+ }
+ this.delegate = delegate;
+ this.wrapperFactory = headlessViewer;
+ this.executionMode = executionMode;
+
+ this.domainObjectContainerResolve = new DomainObjectContainerResolve();
+ this.domainObjectContainerObjectChanged = new DomainObjectContainerObjectChanged();
+
+ try {
+ equalsMethod = delegate.getClass().getMethod("equals", new Class[] { Object.class });
+ hashCodeMethod = delegate.getClass().getMethod("hashCode", new Class[] {});
+ toStringMethod = delegate.getClass().getMethod("toString", new Class[] {});
+ } catch (final NoSuchMethodException e) {
+ // ///CLOVER:OFF
+ throw new RuntimeException("An Object method could not be found: " + e.getMessage());
+ // ///CLOVER:ON
+ }
+ }
+
+ @Override
+ public boolean isResolveObjectChangedEnabled() {
+ return resolveObjectChangedEnabled;
+ }
+
+ @Override
+ public void setResolveObjectChangedEnabled(final boolean resolveObjectChangedEnabled) {
+ this.resolveObjectChangedEnabled = resolveObjectChangedEnabled;
+ }
+
+ protected void resolveIfRequired(final ObjectAdapter targetAdapter) {
+ resolveIfRequired(targetAdapter.getObject());
+ }
+
+ protected void resolveIfRequired(final Object domainObject) {
+ if (resolveObjectChangedEnabled) {
+ domainObjectContainerResolve.resolve(domainObject);
+ }
+ }
+
+ protected void objectChangedIfRequired(final ObjectAdapter targetAdapter) {
+ objectChangedIfRequired(targetAdapter.getObject());
+ }
+
+ protected void objectChangedIfRequired(final Object domainObject) {
+ if (resolveObjectChangedEnabled) {
+ domainObjectContainerObjectChanged.objectChanged(domainObject);
+ }
+ }
+
+ public WrapperFactory getHeadlessViewer() {
+ return wrapperFactory;
+ }
+
+ @Override
+ public T getDelegate() {
+ return delegate;
+ }
+
+ public ExecutionMode getExecutionMode() {
+ return executionMode;
+ }
+
+ protected Object delegate(final Method method, final Object[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+
+ return method.invoke(getDelegate(), args);
+ }
+
+ protected boolean isObjectMethod(final Method method) {
+ return toStringMethod.equals(method) || hashCodeMethod.equals(method) || equalsMethod.equals(method);
+ }
+
+ @Override
+ public Object invoke(final Object object, final Method method, final Object[] args) throws Throwable {
+ return method.invoke(object, args);
+ }
+
+ protected InteractionEvent notifyListeners(final InteractionEvent interactionEvent) {
+ wrapperFactory.notifyListeners(interactionEvent);
+ return interactionEvent;
+ }
+
+}
[2/4] ISIS-772: reimplemented.
Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DomainObjectInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DomainObjectInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DomainObjectInvocationHandler.java
deleted file mode 100644
index ee04b79..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/DomainObjectInvocationHandler.java
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.events.CollectionAccessEvent;
-import org.apache.isis.applib.events.InteractionEvent;
-import org.apache.isis.applib.events.ObjectTitleEvent;
-import org.apache.isis.applib.events.PropertyAccessEvent;
-import org.apache.isis.applib.events.UsabilityEvent;
-import org.apache.isis.applib.events.ValidityEvent;
-import org.apache.isis.applib.events.VisibilityEvent;
-import org.apache.isis.applib.filter.Filter;
-import org.apache.isis.applib.services.wrapper.DisabledException;
-import org.apache.isis.applib.services.wrapper.HiddenException;
-import org.apache.isis.applib.services.wrapper.InteractionException;
-import org.apache.isis.applib.services.wrapper.InvalidException;
-import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.applib.services.wrapper.WrapperObject;
-import org.apache.isis.applib.services.wrapper.WrapperFactory.ExecutionMode;
-import org.apache.isis.core.commons.authentication.AuthenticationSession;
-import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
-import org.apache.isis.core.metamodel.adapter.util.AdapterUtils;
-import org.apache.isis.core.metamodel.consent.Consent;
-import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod;
-import org.apache.isis.core.metamodel.consent.InteractionResult;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facets.ImperativeFacet;
-import org.apache.isis.core.metamodel.facets.accessor.PropertyOrCollectionAccessorFacet;
-import org.apache.isis.core.metamodel.facets.actions.choices.ActionChoicesFacet;
-import org.apache.isis.core.metamodel.facets.actions.defaults.ActionDefaultsFacet;
-import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
-import org.apache.isis.core.metamodel.facets.collections.modify.CollectionRemoveFromFacet;
-import org.apache.isis.core.metamodel.facets.param.choices.ActionParameterChoicesFacet;
-import org.apache.isis.core.metamodel.facets.properties.choices.PropertyChoicesFacet;
-import org.apache.isis.core.metamodel.facets.properties.defaults.PropertyDefaultFacet;
-import org.apache.isis.core.metamodel.facets.properties.modify.PropertyInitializationFacet;
-import org.apache.isis.core.metamodel.facets.properties.modify.PropertySetterFacet;
-import org.apache.isis.core.metamodel.interactions.ObjectTitleContext;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.spec.SpecificationLoader;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
-import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
-import org.apache.isis.core.progmodel.facets.actions.validate.method.ActionValidationFacetViaMethod;
-import org.apache.isis.core.progmodel.facets.collections.validate.CollectionValidateAddToFacetViaMethod;
-import org.apache.isis.core.progmodel.facets.collections.validate.CollectionValidateRemoveFromFacetViaMethod;
-import org.apache.isis.core.progmodel.facets.members.disabled.method.DisableForContextFacetViaMethod;
-import org.apache.isis.core.progmodel.facets.members.hidden.method.HideForContextFacetViaMethod;
-import org.apache.isis.core.progmodel.facets.properties.modify.PropertyClearFacetViaClearMethod;
-import org.apache.isis.core.progmodel.facets.properties.modify.PropertySetterFacetViaModifyMethod;
-import org.apache.isis.core.progmodel.facets.properties.validate.PropertyValidateFacetViaMethod;
-
-public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandlerDefault<T> {
-
- private final Map<Method, Collection<?>> collectionViewObjectsByMethod = new HashMap<Method, Collection<?>>();
- private final Map<Method, Map<?, ?>> mapViewObjectsByMethod = new HashMap<Method, Map<?, ?>>();
-
- private final AuthenticationSessionProvider authenticationSessionProvider;
- private final SpecificationLoader specificationLookup;
- private final AdapterManager adapterManager;
- private final ObjectPersistor objectPersistor;
-
- /**
- * The <tt>title()</tt> method; may be <tt>null</tt>.
- */
- protected Method titleMethod;
-
- /**
- * The <tt>save()</tt> method from {@link WrapperObject#save()}.
- */
- protected Method saveMethod;
-
- /**
- * The <tt>underlying()</tt> method from {@link WrapperObject#wrapped()}.
- */
- protected Method wrappedMethod;
-
- public DomainObjectInvocationHandler(final T delegate, final WrapperFactory embeddedViewer, final ExecutionMode mode, final AuthenticationSessionProvider authenticationSessionProvider, final SpecificationLoader specificationLookup, final AdapterManager adapterManager,
- final ObjectPersistor objectPersistor) {
- super(delegate, embeddedViewer, mode);
-
- this.authenticationSessionProvider = authenticationSessionProvider;
- this.specificationLookup = specificationLookup;
- this.adapterManager = adapterManager;
- this.objectPersistor = objectPersistor;
-
- try {
- titleMethod = delegate.getClass().getMethod("title", new Class[] {});
- saveMethod = WrapperObject.class.getMethod("save", new Class[] {});
- wrappedMethod = WrapperObject.class.getMethod("wrapped", new Class[] {});
- } catch (final NoSuchMethodException e) {
- }
- }
-
- @Override
- public Object invoke(final Object proxyObject, final Method method, final Object[] args) throws Throwable {
-
- if (isObjectMethod(method)) {
- return delegate(method, args);
- }
-
- // workaround for JDO-enhanced..
- if(isJdoMethod(method)) {
- return delegate(method, args);
- }
-
- if(isInjectMethod(method)) {
- return delegate(method, args);
- }
-
- final ObjectAdapter targetAdapter = getAdapterManager().getAdapterFor(getDelegate());
-
- if (isTitleMethod(method)) {
- return handleTitleMethod(method, args, targetAdapter);
- }
-
-
-
- final ObjectSpecification targetNoSpec = targetAdapter.getSpecification();
-
- // save method, through the proxy
- if (isSaveMethod(method)) {
- return handleSaveMethod(getAuthenticationSession(), targetAdapter, targetNoSpec);
- }
-
- if (isUnderlyingMethod(method)) {
- return getDelegate();
- }
-
- final ObjectMember objectMember = locateAndCheckMember(method);
- final List<Facet> imperativeFacets = getImperativeFacets(objectMember, method);
-
- final String memberName = objectMember.getName();
-
- if (instanceOf(imperativeFacets, DisableForContextFacetViaMethod.class, HideForContextFacetViaMethod.class)) {
- throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'", memberName));
- }
-
- final String methodName = method.getName();
-
- if (instanceOf(imperativeFacets, ActionDefaultsFacet.class, PropertyDefaultFacet.class, ActionChoicesFacet.class, ActionParameterChoicesFacet.class, PropertyChoicesFacet.class)) {
- return method.invoke(getDelegate(), args);
- }
-
- // for all members, check visibility and usability
- checkVisibility(getAuthenticationSession(), targetAdapter, objectMember);
-
- if (objectMember.isOneToOneAssociation()) {
-
- if (instanceOf(imperativeFacets, PropertyValidateFacetViaMethod.class, PropertySetterFacetViaModifyMethod.class, PropertyClearFacetViaClearMethod.class)) {
- throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'; use only property accessor/mutator", memberName));
- }
-
- final OneToOneAssociation otoa = (OneToOneAssociation) objectMember;
- if (instanceOf(imperativeFacets, PropertyOrCollectionAccessorFacet.class)) {
- return handleGetterMethodOnProperty(args, targetAdapter, otoa, methodName);
- }
- if (instanceOf(imperativeFacets, PropertySetterFacet.class, PropertyInitializationFacet.class)) {
- checkUsability(getAuthenticationSession(), targetAdapter, objectMember);
- return handleSetterMethodOnProperty(args, getAuthenticationSession(), targetAdapter, otoa, methodName);
- }
- }
- if (objectMember.isOneToManyAssociation()) {
-
- if (instanceOf(imperativeFacets, CollectionValidateAddToFacetViaMethod.class, CollectionValidateRemoveFromFacetViaMethod.class)) {
- throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'; use only collection accessor/mutator", memberName));
- }
-
- final OneToManyAssociation otma = (OneToManyAssociation) objectMember;
- if (instanceOf(imperativeFacets, PropertyOrCollectionAccessorFacet.class)) {
- return handleGetterMethodOnCollection(method, args, targetAdapter, otma, memberName);
- }
- if (instanceOf(imperativeFacets, CollectionAddToFacet.class)) {
- checkUsability(getAuthenticationSession(), targetAdapter, objectMember);
- return handleCollectionAddToMethod(args, targetAdapter, otma, methodName);
- }
- if (instanceOf(imperativeFacets, CollectionRemoveFromFacet.class)) {
- checkUsability(getAuthenticationSession(), targetAdapter, objectMember);
- return handleCollectionRemoveFromMethod(args, targetAdapter, otma, methodName);
- }
- }
-
- // filter out
- if (instanceOf(imperativeFacets, PropertyOrCollectionAccessorFacet.class)) {
- throw new UnsupportedOperationException(String.format("Can only invoke accessor on properties or collections; '%s' represents %s", methodName, decode(objectMember)));
- }
- if (instanceOf(imperativeFacets, PropertySetterFacet.class)) {
- throw new UnsupportedOperationException(String.format("Can only invoke mutator on properties; '%s' represents %s", methodName, decode(objectMember)));
- }
- if (instanceOf(imperativeFacets, CollectionAddToFacet.class)) {
- throw new UnsupportedOperationException(String.format("Can only invoke 'adder' on collections; '%s' represents %s", methodName, decode(objectMember)));
- }
- if (instanceOf(imperativeFacets, CollectionRemoveFromFacet.class)) {
- throw new UnsupportedOperationException(String.format("Can only invoke 'remover' on collections; '%s' represents %s", methodName, decode(objectMember)));
- }
-
- if (objectMember instanceof ObjectAction) {
-
- if (instanceOf(imperativeFacets, ActionValidationFacetViaMethod.class)) {
- throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'; use only the 'invoke' method", memberName));
- }
-
- checkUsability(getAuthenticationSession(), targetAdapter, objectMember);
-
- final ObjectAction noa = (ObjectAction) objectMember;
- return handleActionMethod(args, getAuthenticationSession(), targetAdapter, noa, memberName);
- }
-
- throw new UnsupportedOperationException(String.format("Unknown member type '%s'", objectMember));
- }
-
- private boolean isJdoMethod(final Method method) {
- return methodStartsWith(method, "jdo");
- }
-
- private boolean isInjectMethod(final Method method) {
- return methodStartsWith(method, "inject");
- }
-
- private boolean methodStartsWith(final Method method, final String prefix) {
- return method.getName().startsWith(prefix);
- }
-
- public List<Facet> getImperativeFacets(final ObjectMember objectMember, final Method method) {
- final List<Facet> imperativeFacets = objectMember.getFacets(new Filter<Facet>() {
- @Override
- public boolean accept(final Facet facet) {
- final ImperativeFacet imperativeFacet = asImperativeFacet(facet);
- if (imperativeFacet == null) {
- return false;
- }
- return imperativeFacet.getMethods().contains(method);
- }
-
- private ImperativeFacet asImperativeFacet(final Facet facet) {
- if (facet == null) {
- return null;
- }
- if (facet instanceof ImperativeFacet) {
- return (ImperativeFacet) facet;
- }
- return asImperativeFacet(facet.getUnderlyingFacet());
- }
- });
-
- // there will be at least one
- if (imperativeFacets.isEmpty()) {
- throw new IllegalStateException("should be at least one imperative facet");
- }
- return imperativeFacets;
- }
-
- private static boolean instanceOf(final List<?> objects, final Class<?>... superTypes) {
- for (final Class<?> superType : superTypes) {
- for (final Object obj : objects) {
- if (superType.isAssignableFrom(obj.getClass())) {
- return true;
- }
- }
- }
- return false;
- }
-
- // /////////////////////////////////////////////////////////////////
- // title
- // /////////////////////////////////////////////////////////////////
-
- private Object handleTitleMethod(final Method method, final Object[] args, final ObjectAdapter targetAdapter) throws IllegalAccessException, InvocationTargetException {
-
- resolveIfRequired(targetAdapter);
-
- final ObjectSpecification targetNoSpec = targetAdapter.getSpecification();
- final ObjectTitleContext titleContext = targetNoSpec.createTitleInteractionContext(getAuthenticationSession(), InteractionInvocationMethod.BY_USER, targetAdapter);
- final ObjectTitleEvent titleEvent = titleContext.createInteractionEvent();
- notifyListeners(titleEvent);
- return titleEvent.getTitle();
- }
-
- // /////////////////////////////////////////////////////////////////
- // save
- // /////////////////////////////////////////////////////////////////
-
- private Object handleSaveMethod(final AuthenticationSession session, final ObjectAdapter targetAdapter, final ObjectSpecification targetNoSpec) {
-
- final InteractionResult interactionResult = targetNoSpec.isValidResult(targetAdapter);
- notifyListenersAndVetoIfRequired(interactionResult);
-
- if (getExecutionMode() == ExecutionMode.EXECUTE) {
- if (targetAdapter.isTransient()) {
- getObjectPersistor().makePersistent(targetAdapter);
- }
- }
- return null;
- }
-
- // /////////////////////////////////////////////////////////////////
- // property - access
- // /////////////////////////////////////////////////////////////////
-
- private Object handleGetterMethodOnProperty(final Object[] args, final ObjectAdapter targetAdapter, final OneToOneAssociation otoa, final String methodName) {
- if (args.length != 0) {
- throw new IllegalArgumentException("Invoking a 'get' should have no arguments");
- }
-
- resolveIfRequired(targetAdapter);
-
- final ObjectAdapter currentReferencedAdapter = otoa.get(targetAdapter);
- final Object currentReferencedObj = AdapterUtils.unwrap(currentReferencedAdapter);
-
- final PropertyAccessEvent ev = new PropertyAccessEvent(getDelegate(), otoa.getIdentifier(), currentReferencedObj);
- notifyListeners(ev);
- return currentReferencedObj;
- }
-
- // /////////////////////////////////////////////////////////////////
- // property - modify
- // /////////////////////////////////////////////////////////////////
-
- private Object handleSetterMethodOnProperty(final Object[] args, final AuthenticationSession session, final ObjectAdapter targetAdapter, final OneToOneAssociation otoa, final String methodName) {
- if (args.length != 1) {
- throw new IllegalArgumentException("Invoking a setter should only have a single argument");
- }
-
- resolveIfRequired(targetAdapter);
-
- final Object argumentObj = underlying(args[0]);
- final ObjectAdapter argumentAdapter = argumentObj != null ? getAdapterManager().adapterFor(argumentObj) : null;
-
- final InteractionResult interactionResult = otoa.isAssociationValid(targetAdapter, argumentAdapter).getInteractionResult();
- notifyListenersAndVetoIfRequired(interactionResult);
-
- if (getExecutionMode() == ExecutionMode.EXECUTE) {
- otoa.set(targetAdapter, argumentAdapter);
- }
-
- objectChangedIfRequired(targetAdapter);
-
- return null;
- }
-
- // /////////////////////////////////////////////////////////////////
- // collection - access
- // /////////////////////////////////////////////////////////////////
-
- private Object handleGetterMethodOnCollection(final Method method, final Object[] args, final ObjectAdapter targetAdapter, final OneToManyAssociation otma, final String memberName) {
- if (args.length != 0) {
- throw new IllegalArgumentException("Invoking a 'get' should have no arguments");
- }
-
- resolveIfRequired(targetAdapter);
-
- final ObjectAdapter currentReferencedAdapter = otma.get(targetAdapter);
- final Object currentReferencedObj = AdapterUtils.unwrap(currentReferencedAdapter);
-
- final CollectionAccessEvent ev = new CollectionAccessEvent(getDelegate(), otma.getIdentifier());
-
- if (currentReferencedObj instanceof Collection) {
- final Collection<?> collectionViewObject = lookupViewObject(method, memberName, (Collection<?>) currentReferencedObj, otma);
- notifyListeners(ev);
- return collectionViewObject;
- } else if (currentReferencedObj instanceof Map) {
- final Map<?, ?> mapViewObject = lookupViewObject(method, memberName, (Map<?, ?>) currentReferencedObj, otma);
- notifyListeners(ev);
- return mapViewObject;
- }
- throw new IllegalArgumentException(String.format("Collection type '%s' not supported by framework", currentReferencedObj.getClass().getName()));
- }
-
- /**
- * Looks up (or creates) a proxy for this object.
- */
- private Collection<?> lookupViewObject(final Method method, final String memberName, final Collection<?> collectionToLookup, final OneToManyAssociation otma) {
- Collection<?> collectionViewObject = collectionViewObjectsByMethod.get(method);
- if (collectionViewObject == null) {
- if (collectionToLookup instanceof WrapperObject) {
- collectionViewObject = collectionToLookup;
- } else {
- collectionViewObject = Proxy.proxy(collectionToLookup, memberName, this, otma);
- }
- collectionViewObjectsByMethod.put(method, collectionViewObject);
- }
- return collectionViewObject;
- }
-
- private Map<?, ?> lookupViewObject(final Method method, final String memberName, final Map<?, ?> mapToLookup, final OneToManyAssociation otma) {
- Map<?, ?> mapViewObject = mapViewObjectsByMethod.get(method);
- if (mapViewObject == null) {
- if (mapToLookup instanceof WrapperObject) {
- mapViewObject = mapToLookup;
- } else {
- mapViewObject = Proxy.proxy(mapToLookup, memberName, this, otma);
- }
- mapViewObjectsByMethod.put(method, mapViewObject);
- }
- return mapViewObject;
- }
-
- // /////////////////////////////////////////////////////////////////
- // collection - add to
- // /////////////////////////////////////////////////////////////////
-
- private Object handleCollectionAddToMethod(final Object[] args, final ObjectAdapter targetAdapter, final OneToManyAssociation otma, final String methodName) {
-
- if (args.length != 1) {
- throw new IllegalArgumentException("Invoking a addTo should only have a single argument");
- }
-
- resolveIfRequired(targetAdapter);
-
- final Object argumentObj = underlying(args[0]);
- if (argumentObj == null) {
- throw new IllegalArgumentException("Must provide a non-null object to add");
- }
- final ObjectAdapter argumentNO = getAdapterManager().adapterFor(argumentObj);
-
- final InteractionResult interactionResult = otma.isValidToAdd(targetAdapter, argumentNO).getInteractionResult();
- notifyListenersAndVetoIfRequired(interactionResult);
-
- if (getExecutionMode() == ExecutionMode.EXECUTE) {
- otma.addElement(targetAdapter, argumentNO);
- }
-
- objectChangedIfRequired(targetAdapter);
-
- return null;
- }
-
- // /////////////////////////////////////////////////////////////////
- // collection - remove from
- // /////////////////////////////////////////////////////////////////
-
- private Object handleCollectionRemoveFromMethod(final Object[] args, final ObjectAdapter targetAdapter, final OneToManyAssociation otma, final String methodName) {
- if (args.length != 1) {
- throw new IllegalArgumentException("Invoking a removeFrom should only have a single argument");
- }
-
- resolveIfRequired(targetAdapter);
-
- final Object argumentObj = underlying(args[0]);
- if (argumentObj == null) {
- throw new IllegalArgumentException("Must provide a non-null object to remove");
- }
- final ObjectAdapter argumentAdapter = getAdapterManager().adapterFor(argumentObj);
-
- final InteractionResult interactionResult = otma.isValidToRemove(targetAdapter, argumentAdapter).getInteractionResult();
- notifyListenersAndVetoIfRequired(interactionResult);
-
- if (getExecutionMode() == ExecutionMode.EXECUTE) {
- otma.removeElement(targetAdapter, argumentAdapter);
- }
-
- objectChangedIfRequired(targetAdapter);
-
- return null;
- }
-
- // /////////////////////////////////////////////////////////////////
- // action
- // /////////////////////////////////////////////////////////////////
-
- private Object handleActionMethod(final Object[] args, final AuthenticationSession session, final ObjectAdapter targetAdapter, final ObjectAction noa, final String memberName) {
-
- final Object[] underlyingArgs = new Object[args.length];
- int i = 0;
- for (final Object arg : args) {
- underlyingArgs[i++] = underlying(arg);
- }
-
- final ObjectAdapter[] argAdapters = new ObjectAdapter[underlyingArgs.length];
- int j = 0;
- for (final Object underlyingArg : underlyingArgs) {
- argAdapters[j++] = underlyingArg != null ? getAdapterManager().adapterFor(underlyingArg) : null;
- }
-
- final InteractionResult interactionResult = noa.isProposedArgumentSetValid(targetAdapter, argAdapters).getInteractionResult();
- notifyListenersAndVetoIfRequired(interactionResult);
-
- if (getExecutionMode() == ExecutionMode.EXECUTE) {
- final ObjectAdapter actionReturnNO = noa.execute(targetAdapter, argAdapters);
- return AdapterUtils.unwrap(actionReturnNO);
- }
-
- objectChangedIfRequired(targetAdapter);
-
- return null;
- }
-
- private Object underlying(final Object arg) {
- if (arg instanceof WrapperObject) {
- final WrapperObject argViewObject = (WrapperObject) arg;
- return argViewObject.wrapped();
- } else {
- return arg;
- }
- }
-
- // /////////////////////////////////////////////////////////////////
- // visibility and usability checks (common to all members)
- // /////////////////////////////////////////////////////////////////
-
- /**
- * REVIEW: ideally should provide some way to allow to caller to indicate the 'where' context. Having
- * a hard-coded value like this is an approximation.
- */
- private final Where where = Where.ANYWHERE;
-
- private void checkVisibility(final AuthenticationSession session, final ObjectAdapter targetObjectAdapter, final ObjectMember objectMember) {
- final Consent visibleConsent = objectMember.isVisible(getAuthenticationSession(), targetObjectAdapter, where);
- final InteractionResult interactionResult = visibleConsent.getInteractionResult();
- notifyListenersAndVetoIfRequired(interactionResult);
- }
-
- private void checkUsability(final AuthenticationSession session, final ObjectAdapter targetObjectAdapter, final ObjectMember objectMember) {
- final InteractionResult interactionResult = objectMember.isUsable(getAuthenticationSession(), targetObjectAdapter, where).getInteractionResult();
- notifyListenersAndVetoIfRequired(interactionResult);
- }
-
- // /////////////////////////////////////////////////////////////////
- // notify listeners
- // /////////////////////////////////////////////////////////////////
-
- private void notifyListenersAndVetoIfRequired(final InteractionResult interactionResult) {
- final InteractionEvent interactionEvent = interactionResult.getInteractionEvent();
- notifyListeners(interactionEvent);
- if (interactionEvent.isVeto()) {
- throw toException(interactionEvent);
- }
- }
-
- private String decode(final ObjectMember objectMember) {
- if (objectMember instanceof OneToOneAssociation) {
- return "a property";
- }
- if (objectMember instanceof OneToManyAssociation) {
- return "a collection";
- }
- if (objectMember instanceof ObjectAction) {
- return "an action";
- }
- return "an UNKNOWN member type";
- }
-
- /**
- * Wraps a {@link InteractionEvent#isVeto() vetoing}
- * {@link InteractionEvent} in a corresponding {@link InteractionException},
- * and returns it.
- */
- private InteractionException toException(final InteractionEvent interactionEvent) {
- if (!interactionEvent.isVeto()) {
- throw new IllegalArgumentException("Provided interactionEvent must be a veto");
- }
- if (interactionEvent instanceof ValidityEvent) {
- final ValidityEvent validityEvent = (ValidityEvent) interactionEvent;
- return new InvalidException(validityEvent);
- }
- if (interactionEvent instanceof VisibilityEvent) {
- final VisibilityEvent visibilityEvent = (VisibilityEvent) interactionEvent;
- return new HiddenException(visibilityEvent);
- }
- if (interactionEvent instanceof UsabilityEvent) {
- final UsabilityEvent usabilityEvent = (UsabilityEvent) interactionEvent;
- return new DisabledException(usabilityEvent);
- }
- throw new IllegalArgumentException("Provided interactionEvent must be a VisibilityEvent, UsabilityEvent or a ValidityEvent");
- }
-
- // /////////////////////////////////////////////////////////////////
- // switching
- // /////////////////////////////////////////////////////////////////
-
- private ObjectMember locateAndCheckMember(final Method method) {
- final ObjectSpecificationDefault objectSpecificationDefault = getJavaSpecificationOfOwningClass(method);
- final ObjectMember member = objectSpecificationDefault.getMember(method);
-
- if (member == null) {
- final String methodName = method.getName();
- throw new UnsupportedOperationException("Method '" + methodName + "' being invoked does not correspond to any of the object's fields or actions.");
- }
- return member;
- }
-
- protected boolean isTitleMethod(final Method method) {
- return method.equals(titleMethod);
- }
-
- protected boolean isSaveMethod(final Method method) {
- return method.equals(saveMethod);
- }
-
- protected boolean isUnderlyingMethod(final Method method) {
- return method.equals(wrappedMethod);
- }
-
- // /////////////////////////////////////////////////////////////////
- // Specification lookup
- // /////////////////////////////////////////////////////////////////
-
- private ObjectSpecificationDefault getJavaSpecificationOfOwningClass(final Method method) {
- return getJavaSpecification(method.getDeclaringClass());
- }
-
- private ObjectSpecificationDefault getJavaSpecification(final Class<?> clazz) {
- final ObjectSpecification nos = getSpecification(clazz);
- if (!(nos instanceof ObjectSpecificationDefault)) {
- throw new UnsupportedOperationException("Only Java is supported (specification is '" + nos.getClass().getCanonicalName() + "')");
- }
- return (ObjectSpecificationDefault) nos;
- }
-
- private ObjectSpecification getSpecification(final Class<?> type) {
- final ObjectSpecification nos = getSpecificationLookup().loadSpecification(type);
- return nos;
- }
-
- // /////////////////////////////////////////////////////////////////
- // Dependencies
- // /////////////////////////////////////////////////////////////////
-
- protected SpecificationLoader getSpecificationLookup() {
- return specificationLookup;
- }
-
- public AuthenticationSessionProvider getAuthenticationSessionProvider() {
- return authenticationSessionProvider;
- }
-
- protected AuthenticationSession getAuthenticationSession() {
- return getAuthenticationSessionProvider().getAuthenticationSession();
- }
-
- protected AdapterManager getAdapterManager() {
- return adapterManager;
- }
-
- protected ObjectPersistor getObjectPersistor() {
- return objectPersistor;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/IClassInstantiatorCE.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/IClassInstantiatorCE.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/IClassInstantiatorCE.java
deleted file mode 100644
index 9b471a5..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/IClassInstantiatorCE.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-/**
- * Used to instantiate a given class.
- */
-interface IClassInstantiatorCE {
-
- /**
- * Return a new instance of the specified class. The recommended way is
- * without calling any constructor. This is usually done by doing like
- * <code>ObjectInputStream.readObject()</code> which is JVM specific.
- *
- * @param c
- * Class to instantiate
- * @return new instance of clazz
- */
- Object newInstance(Class<?> clazz) throws InstantiationException;
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/IProxyFactory.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/IProxyFactory.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/IProxyFactory.java
deleted file mode 100644
index 86c35f9..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/IProxyFactory.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.lang.reflect.InvocationHandler;
-
-public interface IProxyFactory<T> {
- T createProxy(Class<T> toProxyClass, InvocationHandler handler);
-
- T createProxy(T toProxy, InvocationHandler handler);
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InteractionEventDispatcher.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InteractionEventDispatcher.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InteractionEventDispatcher.java
deleted file mode 100644
index 04585d2..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InteractionEventDispatcher.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import org.apache.isis.applib.events.InteractionEvent;
-
-public interface InteractionEventDispatcher {
-
- void dispatch(InteractionEvent interactionEvent);
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InteractionEventDispatcherTypeSafe.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InteractionEventDispatcherTypeSafe.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InteractionEventDispatcherTypeSafe.java
deleted file mode 100644
index 7fa3735..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InteractionEventDispatcherTypeSafe.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import org.apache.isis.applib.events.InteractionEvent;
-
-public abstract class InteractionEventDispatcherTypeSafe<T extends InteractionEvent> implements InteractionEventDispatcher {
-
- public abstract void dispatchTypeSafe(T interactionEvent);
-
- @Override
- @SuppressWarnings("unchecked")
- public void dispatch(final InteractionEvent interactionEvent) {
- dispatchTypeSafe((T) interactionEvent);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InvocationHandlerMethodInterceptor.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InvocationHandlerMethodInterceptor.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InvocationHandlerMethodInterceptor.java
deleted file mode 100644
index 0cf6c82..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/InvocationHandlerMethodInterceptor.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-
-import net.sf.cglib.proxy.MethodInterceptor;
-import net.sf.cglib.proxy.MethodProxy;
-
-public class InvocationHandlerMethodInterceptor implements MethodInterceptor {
- private final InvocationHandler handler;
-
- InvocationHandlerMethodInterceptor(final InvocationHandler handler) {
- this.handler = handler;
- }
-
- @Override
- public Object intercept(final Object obj, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable {
- return handler.invoke(obj, method, args);
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/JavaProxyFactory.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/JavaProxyFactory.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/JavaProxyFactory.java
deleted file mode 100644
index efeeb1d..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/JavaProxyFactory.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
-
-import org.apache.isis.applib.services.wrapper.WrapperObject;
-
-public class JavaProxyFactory<T> implements IProxyFactory<T> {
- @Override
- @SuppressWarnings("unchecked")
- public T createProxy(final T toProxy, final InvocationHandler handler) {
- final Class<T> proxyClass = (Class<T>) toProxy.getClass();
- return (T) Proxy.newProxyInstance(proxyClass.getClassLoader(), new Class[] { proxyClass }, handler);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public T createProxy(final Class<T> toProxy, final InvocationHandler handler) {
- return (T) Proxy.newProxyInstance(toProxy.getClassLoader(), new Class[] { toProxy, WrapperObject.class }, handler);
- }
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/MapInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/MapInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/MapInvocationHandler.java
deleted file mode 100644
index b78b880..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/MapInvocationHandler.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import java.util.Map;
-
-import org.apache.isis.core.commons.lang.ObjectExtensions;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
-
-class MapInvocationHandler<T, C> extends AbstractCollectionInvocationHandler<T, C> {
-
- public MapInvocationHandler(final C collectionToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
- super(collectionToProxy, collectionName, handler, otma);
-
- try {
- intercept(ObjectExtensions.getMethod(collectionToProxy, "containsKey", Object.class));
- intercept(ObjectExtensions.getMethod(collectionToProxy, "containsValue", Object.class));
- intercept(ObjectExtensions.getMethod(collectionToProxy, "size"));
- intercept(ObjectExtensions.getMethod(collectionToProxy, "isEmpty"));
- veto(ObjectExtensions.getMethod(collectionToProxy, "put", Object.class, Object.class));
- veto(ObjectExtensions.getMethod(collectionToProxy, "remove", Object.class));
- veto(ObjectExtensions.getMethod(collectionToProxy, "putAll", Map.class));
- veto(ObjectExtensions.getMethod(collectionToProxy, "clear"));
- } catch (final NoSuchMethodException e) {
- // ///CLOVER:OFF
- throw new RuntimeException("A Collection method could not be found: " + e.getMessage());
- // ///CLOVER:ON
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/ObjenesisClassInstantiatorCE.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/ObjenesisClassInstantiatorCE.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/ObjenesisClassInstantiatorCE.java
deleted file mode 100644
index bd029d9..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/ObjenesisClassInstantiatorCE.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import org.objenesis.ObjenesisHelper;
-
-class ObjenesisClassInstantiatorCE implements IClassInstantiatorCE {
-
- @Override
- public Object newInstance(final Class<?> clazz) throws InstantiationException {
- return ObjenesisHelper.newInstance(clazz);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/Proxy.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/Proxy.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/Proxy.java
deleted file mode 100644
index 46952c6..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/Proxy.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.nullValue;
-
-import java.util.Collection;
-import java.util.Map;
-
-import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.applib.services.wrapper.WrapperFactory.ExecutionMode;
-import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
-import org.apache.isis.core.commons.ensure.Ensure;
-import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
-import org.apache.isis.core.metamodel.spec.SpecificationLoader;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
-
-public class Proxy {
-
- public static <T> T proxy(final T domainObject, final WrapperFactory wrapperFactory, final ExecutionMode mode, final AuthenticationSessionProvider authenticationSessionProvider, final SpecificationLoader specificationLookup, final AdapterManager adapterManager, final ObjectPersistor objectPersistor) {
-
- Ensure.ensureThatArg(wrapperFactory, is(not(nullValue())));
- Ensure.ensureThatArg(authenticationSessionProvider, is(not(nullValue())));
- Ensure.ensureThatArg(specificationLookup, is(not(nullValue())));
- Ensure.ensureThatArg(adapterManager, is(not(nullValue())));
- Ensure.ensureThatArg(objectPersistor, is(not(nullValue())));
-
- final DomainObjectInvocationHandler<T> invocationHandler = new DomainObjectInvocationHandler<T>(domainObject, wrapperFactory, mode, authenticationSessionProvider, specificationLookup, adapterManager, objectPersistor);
-
- final CgLibProxy<T> cglibProxy = new CgLibProxy<T>(invocationHandler);
- return cglibProxy.proxy();
- }
-
- /**
- * Whether to execute or not will be picked up from the supplied parent
- * handler.
- */
- public static <T, E> Collection<E> proxy(final Collection<E> collectionToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
-
- final CollectionInvocationHandler<T, Collection<E>> collectionInvocationHandler = new CollectionInvocationHandler<T, Collection<E>>(collectionToProxy, collectionName, handler, otma);
- collectionInvocationHandler.setResolveObjectChangedEnabled(handler.isResolveObjectChangedEnabled());
-
- final CgLibProxy<Collection<E>> cglibProxy = new CgLibProxy<Collection<E>>(collectionInvocationHandler);
- return cglibProxy.proxy();
- }
-
- /**
- * Whether to execute or not will be picked up from the supplied parent
- * handler.
- */
- public static <T, P, Q> Map<P, Q> proxy(final Map<P, Q> collectionToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
-
- final MapInvocationHandler<T, Map<P, Q>> mapInvocationHandler = new MapInvocationHandler<T, Map<P, Q>>(collectionToProxy, collectionName, handler, otma);
- mapInvocationHandler.setResolveObjectChangedEnabled(handler.isResolveObjectChangedEnabled());
-
- final CgLibProxy<Map<P, Q>> cglibProxy = new CgLibProxy<Map<P, Q>>(mapInvocationHandler);
- return cglibProxy.proxy();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/RuntimeExceptionWrapper.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/RuntimeExceptionWrapper.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/RuntimeExceptionWrapper.java
deleted file mode 100644
index ef2feda..0000000
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/RuntimeExceptionWrapper.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.core.wrapper.internal;
-
-public class RuntimeExceptionWrapper extends RuntimeException {
- private static final long serialVersionUID = 1L;
- private final RuntimeException runtimeException;
-
- public RuntimeExceptionWrapper(final RuntimeException runtimeException) {
- this.runtimeException = runtimeException;
- }
-
- public RuntimeException getRuntimeException() {
- return runtimeException;
- }
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/util/Util.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/util/Util.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/util/Util.java
new file mode 100644
index 0000000..7cfecbd
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/internal/util/Util.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.internal.util;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+
+import org.objenesis.ObjenesisHelper;
+
+public final class Util {
+
+ private Util(){}
+
+ @SuppressWarnings("unchecked")
+ public static <T> T createInstance(final Class<T> toProxy, final InvocationHandler handler, final Class<?>... auxiliaryTypes) {
+ return (T) Proxy.newProxyInstance(toProxy.getClassLoader(), combine(toProxy, auxiliaryTypes) , handler);
+ }
+
+ /**
+ * Return a new instance of the specified class. The recommended way is
+ * without calling any constructor. This is usually done by doing like
+ * <code>ObjectInputStream.readObject()</code> which is JVM specific.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T createInstance(final Class<T> enhancedClass) {
+ return (T) ObjenesisHelper.newInstance(enhancedClass);
+ }
+
+ private static Class<?>[] combine(Class<?> first, Class<?>... rest) {
+ Class<?>[] all = new Class<?>[rest.length+1];
+ all[0] = first;
+ System.arraycopy(rest, 0, all, 1, rest.length);
+ return all;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiator.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiator.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiator.java
new file mode 100644
index 0000000..255cbfa
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiator.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.proxy;
+
+import org.apache.isis.core.wrapper.handlers.DelegatingInvocationHandler;
+
+public interface ProxyInstantiator {
+ public <T> T instantiateProxy(final DelegatingInvocationHandler<T> invocationHandler);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiatorForCglib.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiatorForCglib.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiatorForCglib.java
new file mode 100644
index 0000000..65241e9
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiatorForCglib.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.proxy;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.Factory;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
+
+import org.apache.isis.applib.services.wrapper.WrapperObject;
+import org.apache.isis.core.metamodel.specloader.classsubstitutor.CglibEnhanced;
+import org.apache.isis.core.wrapper.handlers.DelegatingInvocationHandler;
+import org.apache.isis.core.wrapper.internal.util.Util;
+
+public class ProxyInstantiatorForCglib implements ProxyInstantiator {
+
+ @SuppressWarnings("unchecked")
+ public <T> T instantiateProxy(final DelegatingInvocationHandler<T> handler) {
+
+ final T toProxy = handler.getDelegate();
+
+ // handle if already proxied using cglib
+ // (this is in case the CglibObjectFactory is configured, to handle lazy loading/object dirtying.
+ // Have decided not to port this over to the Javassist version, in anticipation of the CglibObjectFactory being dropped from Isis in v2.0.0.
+ // (If that isn't the case, then this class is still available).
+ if (CglibEnhanced.class.isAssignableFrom(toProxy.getClass())) {
+
+ handler.setResolveObjectChangedEnabled(true);
+
+ final Class<? extends Object> enhancedClass = toProxy.getClass();
+ final Class<? extends Object> origSuperclass = toProxy.getClass().getSuperclass();
+
+ final List<Class<?>> interfaces = Lists.newArrayList();
+ interfaces.addAll(Arrays.asList(enhancedClass.getInterfaces()));
+ interfaces.remove(Factory.class); // if there.
+ interfaces.add(WrapperObject.class);
+
+ return (T) Enhancer.create(origSuperclass, interfaces.toArray(new Class[] {}), newMethodInterceptor(handler));
+ }
+
+ final Class<T> clazz = (Class<T>) toProxy.getClass();
+
+ if (clazz.isInterface()) {
+ return Util.createInstance(clazz, handler, WrapperObject.class);
+ } else {
+ final Class<T> enhancedClass = createEnhancedClass(clazz, handler, WrapperObject.class);
+ return Util.createInstance(enhancedClass);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> Class<T> createEnhancedClass(final Class<T> toProxyClass, final InvocationHandler handler, final Class<?>... auxiliaryTypes) {
+
+ // Create the proxy
+ final Enhancer enhancer = new Enhancer();
+ enhancer.setSuperclass(toProxyClass);
+ enhancer.setInterfaces(auxiliaryTypes);
+ enhancer.setCallbackType(newMethodInterceptor(handler).getClass());
+
+ final Class<?> enhancedClass = enhancer.createClass();
+
+ Enhancer.registerCallbacks(enhancedClass, new Callback[] { newMethodInterceptor(handler) });
+ return (Class<T>) enhancedClass;
+ }
+
+ private static <T> MethodInterceptor newMethodInterceptor(final InvocationHandler handler) {
+ return new MethodInterceptor() {
+ @Override
+ public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
+ return handler.invoke(obj, method, args);
+ }
+ };
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiatorForJavassist.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiatorForJavassist.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiatorForJavassist.java
new file mode 100644
index 0000000..3d2b838
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/proxy/ProxyInstantiatorForJavassist.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.isis.core.wrapper.proxy;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+import javassist.util.proxy.MethodFilter;
+import javassist.util.proxy.MethodHandler;
+import javassist.util.proxy.ProxyFactory;
+import javassist.util.proxy.ProxyObject;
+
+import org.apache.isis.applib.services.wrapper.WrapperObject;
+import org.apache.isis.core.commons.lang.ArrayExtensions;
+import org.apache.isis.core.wrapper.handlers.DelegatingInvocationHandler;
+import org.apache.isis.core.wrapper.internal.util.Util;
+
+public class ProxyInstantiatorForJavassist implements ProxyInstantiator {
+
+ @SuppressWarnings("unchecked")
+ public <T> T instantiateProxy(final DelegatingInvocationHandler<T> handler) {
+
+ final T toProxy = handler.getDelegate();
+
+ final Class<T> clazz = (Class<T>) toProxy.getClass();
+
+ if (clazz.isInterface()) {
+ return Util.createInstance(clazz, handler, WrapperObject.class);
+ } else {
+ final Class<T> enhancedClass = createEnhancedClass(clazz, handler, WrapperObject.class);
+ ProxyObject proxyObject = (ProxyObject) Util.createInstance(enhancedClass);
+ proxyObject.setHandler(new MethodHandler() {
+ @Override
+ public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
+ return handler.invoke(self, thisMethod, args);
+ }
+ });
+ return (T) proxyObject;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> Class<T> createEnhancedClass(final Class<T> toProxyClass, final InvocationHandler handler, final Class<?>... auxiliaryTypes) {
+
+ final ProxyFactory proxyFactory = new ProxyFactory();
+ proxyFactory.setSuperclass(toProxyClass);
+ proxyFactory.setInterfaces(ArrayExtensions.combine(toProxyClass.getInterfaces(), new Class<?>[]{org.apache.isis.core.metamodel.specloader.classsubstitutor.JavassistEnhanced.class}, auxiliaryTypes));
+
+ proxyFactory.setFilter(new MethodFilter() {
+ @Override
+ public boolean isHandled(final Method m) {
+ // ignore finalize()
+ return !m.getName().equals("finalize") || m.isBridge();
+ }
+ });
+
+ return proxyFactory.createClass();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject.java b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject.java
deleted file mode 100644
index 5a5c653..0000000
--- a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.progmodel.wrapper;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.apache.isis.applib.services.wrapper.DisabledException;
-import org.apache.isis.applib.services.wrapper.HiddenException;
-import org.apache.isis.applib.services.wrapper.InvalidException;
-import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.core.tck.dom.claimapp.employees.Employee;
-import org.apache.isis.core.tck.dom.claimapp.employees.EmployeeRepository;
-import org.apache.isis.core.tck.dom.claimapp.employees.EmployeeRepositoryImpl;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
-import org.apache.isis.core.wrapper.WrapperFactoryDefault;
-
-public class WrappedFactoryDefaultTest_wrappedObject {
-
- @Rule
- public JUnitRuleMockery2 mockery = JUnitRuleMockery2.createFor(Mode.INTERFACES_ONLY);
-
- private EmployeeRepository employeeRepository;
- // private ClaimRepository claimRepository;
-
- private Employee employeeDO;
- private Employee employeeWO;
-
- private WrapperFactory wrapperFactory;
-
- @Before
- public void setUp() {
-
- employeeRepository = new EmployeeRepositoryImpl();
- // claimRepository = new ClaimRepositoryImpl();
-
- employeeDO = new Employee();
- employeeDO.setName("Smith");
- employeeDO.setEmployeeRepository(employeeRepository); // would be done
- // by the
- // EmbeddedContext
- // impl
-
- wrapperFactory = new WrapperFactoryDefault();
- employeeWO = wrapperFactory.wrap(employeeDO);
- }
-
- @Ignore("TODO - moved from embedded runtime, need to re-enable")
- @Test
- public void shouldWrapDomainObject() {
- // then
- assertThat(employeeWO, is(notNullValue()));
- }
-
- @Ignore("TODO - moved from embedded runtime, need to re-enable")
- @Test
- public void shouldBeAbleToInjectIntoDomainObjects() {
-
- // given
- assertThat(employeeDO.getEmployeeRepository(), is(notNullValue()));
-
- // then
- assertThat(employeeWO.getEmployeeRepository(), is(notNullValue()));
- }
-
- @Ignore("TODO - moved from embedded runtime, need to re-enable")
- @Test
- public void shouldBeAbleToReadVisibleProperty() {
- // then
- assertThat(employeeWO.getName(), is(employeeDO.getName()));
- }
-
- @Ignore("TODO - moved from embedded runtime, need to re-enable")
- @Test(expected = HiddenException.class)
- public void shouldNotBeAbleToViewHiddenProperty() {
- // given
- employeeDO.whetherHideName = true;
- // when
- employeeWO.getName();
- // then should throw exception
- }
-
- @Ignore("TODO - moved from embedded runtime, need to re-enable")
- @Test
- public void shouldBeAbleToModifyEnabledPropertyUsingSetter() {
- // when
- employeeWO.setName("Jones");
- // then
- assertThat(employeeDO.getName(), is("Jones"));
- assertThat(employeeWO.getName(), is(employeeDO.getName()));
- }
-
- @Ignore("TODO - moved from embedded runtime, need to re-enable")
- @Test(expected = DisabledException.class)
- public void shouldNotBeAbleToModifyDisabledProperty() {
- // given
- employeeDO.reasonDisableName = "sorry, no change allowed";
- // when
- employeeWO.setName("Jones");
- // then should throw exception
- }
-
- @Ignore("TODO - moved from embedded runtime, need to re-enable")
- @Test(expected = UnsupportedOperationException.class)
- public void shouldNotBeAbleToModifyPropertyUsingModify() {
- // when
- employeeWO.modifyName("Jones");
- // then should throw exception
- }
-
- @Ignore("TODO - moved from embedded runtime, need to re-enable")
- @Test(expected = UnsupportedOperationException.class)
- public void shouldNotBeAbleToModifyPropertyUsingClear() {
- // when
- employeeWO.clearName();
- // then should throw exception
- }
-
- @Ignore("TODO - moved from embedded runtime, need to re-enable")
- @Test(expected = InvalidException.class)
- public void shouldNotBeAbleToModifyPropertyIfInvalid() {
- // given
- employeeDO.reasonValidateName = "sorry, invalid data";
- // when
- employeeWO.setName("Jones");
- // then should throw exception
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/074d2c4e/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject_transient.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject_transient.java b/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject_transient.java
deleted file mode 100644
index 0b11f09..0000000
--- a/core/wrapper/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject_transient.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.isis.progmodel.wrapper;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.jmock.Expectations;
-import org.jmock.auto.Mock;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.events.PropertyModifyEvent;
-import org.apache.isis.applib.events.PropertyUsabilityEvent;
-import org.apache.isis.applib.events.PropertyVisibilityEvent;
-import org.apache.isis.applib.filter.Filter;
-import org.apache.isis.applib.services.wrapper.DisabledException;
-import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
-import org.apache.isis.core.metamodel.consent.Allow;
-import org.apache.isis.core.metamodel.consent.Consent;
-import org.apache.isis.core.metamodel.consent.InteractionResult;
-import org.apache.isis.core.metamodel.consent.Veto;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.spec.SpecificationLoader;
-import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
-import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet;
-import org.apache.isis.core.progmodel.facets.members.disabled.staticmethod.DisabledFacetAlwaysEverywhere;
-import org.apache.isis.core.progmodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor;
-import org.apache.isis.core.progmodel.facets.properties.modify.PropertySetterFacetViaSetterMethod;
-import org.apache.isis.core.runtime.authentication.standard.SimpleSession;
-import org.apache.isis.core.tck.dom.claimapp.employees.Employee;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
-import org.apache.isis.core.wrapper.WrapperFactoryDefault;
-
-public class WrappedFactoryDefaultTest_wrappedObject_transient {
-
- @Rule
- public final JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
-
- @Mock
- private AdapterManager mockAdapterManager;
- @Mock
- private AuthenticationSessionProvider mockAuthenticationSessionProvider;
- @Mock
- private ObjectPersistor mockObjectPersistor;
- @Mock
- private SpecificationLoader mockSpecificationLookup;
-
- private Employee employeeDO;
- @Mock
- private ObjectAdapter mockEmployeeAdapter;
- @Mock
- private ObjectSpecificationDefault mockEmployeeSpec;
- @Mock
- private OneToOneAssociation mockPasswordMember;
- @Mock
- private Identifier mockPasswordIdentifier;
-
- @Mock
- protected ObjectAdapter mockPasswordAdapter;
-
- private final String passwordValue = "12345678";
-
- private final SimpleSession session = new SimpleSession("tester", Collections.<String>emptyList());
-
- private List<Facet> facets;
- private Method getPasswordMethod;
- private Method setPasswordMethod;
-
-
- private WrapperFactoryDefault wrapperFactory;
- private Employee employeeWO;
-
-
- @Before
- public void setUp() throws Exception {
-
- // employeeRepository = new EmployeeRepositoryImpl();
- // claimRepository = new ClaimRepositoryImpl();
-
- employeeDO = new Employee();
- employeeDO.setName("Smith");
-
- getPasswordMethod = Employee.class.getMethod("getPassword");
- setPasswordMethod = Employee.class.getMethod("setPassword", String.class);
-
- wrapperFactory = new WrapperFactoryDefault();
- wrapperFactory.setAdapterManager(mockAdapterManager);
- wrapperFactory.setAuthenticationSessionProvider(mockAuthenticationSessionProvider);
- wrapperFactory.setObjectPersistor(mockObjectPersistor);
- wrapperFactory.setSpecificationLookup(mockSpecificationLookup);
-
- context.checking(new Expectations() {
- {
- allowing(mockAdapterManager).getAdapterFor(employeeDO);
- will(returnValue(mockEmployeeAdapter));
-
- allowing(mockAdapterManager).adapterFor(passwordValue);
- will(returnValue(mockPasswordAdapter));
-
- allowing(mockEmployeeAdapter).getSpecification();
- will(returnValue(mockEmployeeSpec));
-
- allowing(mockEmployeeAdapter).getObject();
- will(returnValue(employeeDO));
-
- allowing(mockPasswordAdapter).getObject();
- will(returnValue(passwordValue));
-
- allowing(mockPasswordMember).getIdentifier();
- will(returnValue(mockPasswordIdentifier));
-
- allowing(mockSpecificationLookup).loadSpecification(Employee.class);
- will(returnValue(mockEmployeeSpec));
-
- allowing(mockEmployeeSpec).getMember(with(setPasswordMethod));
- will(returnValue(mockPasswordMember));
-
- allowing(mockEmployeeSpec).getMember(with(getPasswordMethod));
- will(returnValue(mockPasswordMember));
-
- allowing(mockPasswordMember).getName();
- will(returnValue("password"));
-
- allowing(mockAuthenticationSessionProvider).getAuthenticationSession();
- will(returnValue(session));
-
- allowing(mockPasswordMember).isOneToOneAssociation();
- will(returnValue(true));
-
- allowing(mockPasswordMember).isOneToManyAssociation();
- will(returnValue(false));
- }
- });
-
- employeeWO = wrapperFactory.wrap(employeeDO);
- }
-
- @Test(expected = DisabledException.class)
- public void shouldNotBeAbleToModifyProperty() {
-
- // given
- final DisabledFacet disabledFacet = new DisabledFacetAlwaysEverywhere(mockPasswordMember);
- facets = Arrays.asList((Facet)disabledFacet, new PropertySetterFacetViaSetterMethod(setPasswordMethod, mockPasswordMember));
-
- final Consent visibilityConsent = new Allow(new InteractionResult(new PropertyVisibilityEvent(employeeDO, null)));
-
- final InteractionResult usabilityInteractionResult = new InteractionResult(new PropertyUsabilityEvent(employeeDO, null));
- usabilityInteractionResult.advise("disabled", disabledFacet);
- final Consent usabilityConsent = new Veto(usabilityInteractionResult);
-
- context.checking(new Expectations() {
- {
- allowing(mockPasswordMember).getFacets(with(any(Filter.class)));
- will(returnValue(facets));
-
- allowing(mockPasswordMember).isVisible(session, mockEmployeeAdapter, Where.ANYWHERE);
- will(returnValue(visibilityConsent));
-
- allowing(mockPasswordMember).isUsable(session, mockEmployeeAdapter, Where.ANYWHERE);
- will(returnValue(usabilityConsent));
- }
- });
-
- // when
- employeeWO.setPassword(passwordValue);
-
- // then should throw exception
- }
-
- @Test
- public void canModifyProperty() {
- // given
-
- final Consent visibilityConsent = new Allow(new InteractionResult(new PropertyVisibilityEvent(employeeDO, mockPasswordIdentifier)));
- final Consent usabilityConsent = new Allow(new InteractionResult(new PropertyUsabilityEvent(employeeDO, mockPasswordIdentifier)));
- final Consent validityConsent = new Allow(new InteractionResult(new PropertyModifyEvent(employeeDO, mockPasswordIdentifier, passwordValue)));
-
- context.checking(new Expectations() {
- {
- allowing(mockPasswordMember).isVisible(session, mockEmployeeAdapter, Where.ANYWHERE);
- will(returnValue(visibilityConsent));
-
- allowing(mockPasswordMember).isUsable(session, mockEmployeeAdapter, Where.ANYWHERE);
- will(returnValue(usabilityConsent));
-
- allowing(mockPasswordMember).isAssociationValid(mockEmployeeAdapter, mockPasswordAdapter);
- will(returnValue(validityConsent));
- }
- });
-
- facets = Arrays.asList((Facet)new PropertySetterFacetViaSetterMethod(setPasswordMethod, mockPasswordMember));
- context.checking(new Expectations() {
- {
- one(mockPasswordMember).getFacets(with(any(Filter.class)));
- will(returnValue(facets));
-
- one(mockPasswordMember).set(mockEmployeeAdapter, mockPasswordAdapter);
- }
- });
-
- // when
- employeeWO.setPassword(passwordValue);
-
-
- // and given
- facets = Arrays.asList((Facet)new PropertyAccessorFacetViaAccessor(getPasswordMethod, mockPasswordMember));
- context.checking(new Expectations() {
- {
- one(mockPasswordMember).getFacets(with(any(Filter.class)));
- will(returnValue(facets));
-
- one(mockPasswordMember).get(mockEmployeeAdapter);
- will(returnValue(mockPasswordAdapter));
- }
- });
-
- // then be allowed
- assertThat(employeeWO.getPassword(), is(passwordValue));
- }
-}