/* * � Copyright IBM Corp. 2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ /* * Author: Maire Kehoe (mkehoe@ie.ibm.com) * Date: 30 Nov 2006 * SerializeValueBindingTest.java */ package com.ibm.xsp.test.framework.serialize; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; import javax.faces.component.UIComponent; import javax.faces.component.UIOutput; import javax.faces.context.FacesContext; import javax.faces.el.ValueBinding; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.application.ApplicationExImpl; import com.ibm.xsp.binding.ComponentBindingObject; import com.ibm.xsp.binding.ValueBindingEx; import com.ibm.xsp.complex.ValueBindingObject; import com.ibm.xsp.registry.FacesComplexDefinition; import com.ibm.xsp.registry.FacesDefinition; import com.ibm.xsp.registry.FacesProperty; import com.ibm.xsp.registry.FacesSharableRegistry; import com.ibm.xsp.registry.FacesSimpleProperty; import com.ibm.xsp.registry.RegistryUtil; import com.ibm.xsp.test.framework.AbstractXspTest; import com.ibm.xsp.test.framework.AssertUtil; import com.ibm.xsp.test.framework.TestProject; import com.ibm.xsp.test.framework.XspTestUtil; import com.ibm.xsp.test.framework.setup.SkipFileContent; import com.ibm.xsp.util.StateHolderUtil; /** * @author Maire Kehoe (mkehoe@ie.ibm.com) * 30 Nov 2006 * Unit: SerializeValueBindingTest.java */ public class SerializeValueBindingTest extends AbstractXspTest { /* * The FacesProperty.getJavaClass() classes * handled in createValueBinding */ private Class<?>[] testable = new Class[]{ String.class, Object.class, boolean.class, }; private Map<Class<?>, String> testablePropClassToExpr; @Override public String getDescription() { return "tests serializing "+XspTestUtil.getShortClass(ValueBindingObject.class)+" tags"; } public void testSerializeValueBinding() throws Exception { UIComponent component = new UIOutput(); FacesContext context = TestProject.createFacesContext(this); FacesSharableRegistry reg = TestProject.createRegistry(this); String fails = ""; for (FacesComplexDefinition def : TestProject.getLibComplexDefs(reg, this)) { if( !def.isTag() && (def.getJavaClass().isInterface() || hasModifier(def.getJavaClass(), Modifier.ABSTRACT) )){ // ignore non-tag abstract classes continue; } if( ! ValueBindingObject.class.isAssignableFrom(def.getJavaClass())){ // only test ValueBindingObjects continue; } // create & init tag instance ValueBindingObject instance = (ValueBindingObject) def.getJavaClass().newInstance(); if( instance instanceof ComponentBindingObject ){ ((ComponentBindingObject)instance).setComponent(component); } // find & create value to set FacesSimpleProperty prop = getAllowVBProperty(def); if( null == prop ){ // fake a property to test that save/restore of ValueBindings works prop = (FacesSimpleProperty) RegistryUtil.createFakeProperty("testVBProp", String.class); } ValueBinding vb = createValueBinding(prop, component, context); // set the value instance.setValueBinding(prop.getName(), vb); // serialize & deserialize the tag instance ValueBindingObject restoredInstance; try{ Object state = StateHolderUtil.saveObjectState(context, instance); Object restoreState; { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream serializer = new ObjectOutputStream(out); serializer.writeObject(state); serializer.close(); byte[] serialized = out.toByteArray(); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(serialized)); restoreState = in.readObject(); in.close(); } Object restoredObj = StateHolderUtil.restoreObjectState( context, component, restoreState); restoredInstance = (ValueBindingObject) restoredObj; }catch( Exception e ){ String msg = XspTestUtil.getShortClass(e)+" serializing a "+XspTestUtil.getShortClass(instance); fails += msg +"\n"; System.err.println(SerializeValueBindingTest.class.getName() + ".testSerializeValueBinding() : "+msg); e.printStackTrace(); continue; } // compare the values on the original & deserialized instances ValueBinding restoredVb = restoredInstance.getValueBinding(prop.getName()); if( null == restoredVb ){ fails += XspTestUtil.getShortClass(restoredInstance) + "." + prop.getName() + " VB not restored.\n"; continue; } assertEquals(vb.getExpressionString(), restoredVb.getExpressionString()); if( vb instanceof ValueBindingEx ){ AssertUtil.assertInstanceOf(ValueBindingEx.class, restoredVb); ValueBindingEx expectedVB = (ValueBindingEx) vb; ValueBindingEx actualVB = (ValueBindingEx) restoredVb; if( ! StringUtil.equals(expectedVB.getSourceReferenceId(), actualVB.getSourceReferenceId()) ){ fails += XspTestUtil.getShortClass(restoredInstance) + "." + prop.getName() + " ValueBindingEx.getSourceReferenceId() " + "not equal: " + expectedVB.getSourceReferenceId() + " != " + actualVB.getSourceReferenceId() + ".\n"; continue; } assertEquals(expectedVB.getExpectedType(), actualVB.getExpectedType()); } } fails = XspTestUtil.removeMultilineFailSkips(fails, SkipFileContent.concatSkips(getSkipFails(), this, "testSerializeValueBinding")); if( fails.length() > 0 ){ fail(XspTestUtil.getMultilineFailMessage(fails)); } } protected String[] getSkipFails() { return StringUtil.EMPTY_STRING_ARRAY; } private boolean hasModifier(Class<?> javaClass, int modifierType) { return (0 != (modifierType & javaClass.getModifiers())); } private ValueBinding createValueBinding(FacesSimpleProperty prop, UIComponent component, FacesContext context) { Class<?> propClass = prop.getJavaClass(); if( null == testablePropClassToExpr ){ testablePropClassToExpr = new HashMap<Class<?>, String>(); boolean someJSExpr = false; for (Class<?> clazz : testable) { String exprForClazz = createTestVBExpression(clazz); if( null == exprForClazz ){ fail("Couldn't create VB for "+clazz); throw new RuntimeException(); } testablePropClassToExpr.put(clazz, exprForClazz); if( !someJSExpr ){ someJSExpr = exprForClazz.startsWith("#{javascript:"); } } if(someJSExpr){ assertFalse("javascript VBs require the DesignerApplicationEx, " + "should either depend on ..xsp.designer.library or override the method createTestVBExpression ", context.getApplication().getClass().equals(ApplicationExImpl.class)); } } String expr = testablePropClassToExpr.get(propClass); if( null == expr ){ fail("Couldn't create VB for "+propClass); throw new RuntimeException(); } ValueBinding vb = context.getApplication().createValueBinding(expr); if( vb instanceof ComponentBindingObject ){ ((ComponentBindingObject)vb).setComponent(component); } if( vb instanceof ValueBindingEx ){ ValueBindingEx ex = (ValueBindingEx) vb; ex.setSourceReferenceId("/xp:view/xp:text"); ex.setExpectedType(prop.getJavaClass()); } return vb; } /** * The default implementation uses javascript: expressions * @param propClass * @return */ protected String createTestVBExpression(Class<?> propClass) { String expr = null; // these classes are in the testable array above if( String.class.equals(propClass) ){ expr = "#{javascript: 'testString'}"; } else if( Object.class.equals(propClass) ){ expr = "#{javascript: 'testObject'}"; } else if( boolean.class.equals(propClass) ){ expr = "#{javascript: true}"; } return expr; } private FacesSimpleProperty getAllowVBProperty(FacesDefinition def) { FacesSimpleProperty allowVB = null; for (FacesProperty prop : RegistryUtil.getProperties(def)) { if( prop instanceof FacesSimpleProperty ){ FacesSimpleProperty simple = (FacesSimpleProperty)prop; if (simple.isAllowRunTimeBinding()){ allowVB = simple; if( isTestable(allowVB.getJavaClass()) ) { return allowVB; } } } } return allowVB; } private boolean isTestable(Class<?> javaClass) { for (Class<?> clazz : testable) { if( clazz.equals(javaClass) ){ return true; } } return false; } }