Index: src/main/java/com/sun/enterprise/config/serverbeans/ConnectorResource.java
===================================================================
--- src/main/java/com/sun/enterprise/config/serverbeans/ConnectorResource.java (revision 51804)
+++ src/main/java/com/sun/enterprise/config/serverbeans/ConnectorResource.java (working copy)
@@ -40,6 +40,8 @@
package com.sun.enterprise.config.serverbeans;
+import com.sun.enterprise.config.serverbeans.ConnectorConnectionPool;
+import com.sun.enterprise.config.serverbeans.customvalidators.ReferenceConstraint;
import com.sun.enterprise.config.serverbeans.customvalidators.ResourcePoolReferenceConstraint;
import org.jvnet.hk2.config.Attribute;
import org.jvnet.hk2.config.Element;
@@ -74,7 +76,8 @@
@RestRedirect(opType = RestRedirect.OpType.POST, commandName = "create-connector-resource"),
@RestRedirect(opType = RestRedirect.OpType.DELETE, commandName = "delete-connector-resource")
})
-@ResourcePoolReferenceConstraint(message="{resource.invalid}", payload=ConnectorResource.class)
+//@ResourcePoolReferenceConstraint(message="{resource.invalid}", payload=ConnectorResource.class)
+@ReferenceConstraint(skipDuringCreation=true, payload=ConnectorResource.class)
public interface ConnectorResource extends ConfigBeanProxy, Injectable, Resource,
PropertyBag, BindableResource, Payload {
@@ -87,6 +90,7 @@
*/
@Attribute
@NotNull
+ @ReferenceConstraint.RemoteKey(message="{resourceref.invalid.poolname}", type=ConnectorConnectionPool.class)
String getPoolName();
/**
Index: src/main/java/com/sun/enterprise/config/serverbeans/customvalidators/LocalStrings.properties
===================================================================
--- src/main/java/com/sun/enterprise/config/serverbeans/customvalidators/LocalStrings.properties (revision 51804)
+++ src/main/java/com/sun/enterprise/config/serverbeans/customvalidators/LocalStrings.properties (working copy)
@@ -52,3 +52,6 @@
connpool.custom.validation.classname.mandatory=Must specify 'validation-class-name' when 'connection-validation' is enabled and 'validation-method' is 'custom-validation'. Please specify 'validation-class-name' before enabling 'custom-validation' based validation.
ref.invalid=lb-config can contain references to either server-ref or cluster-ref but not both.
+
+referenceValidator.not.getter=RemoteKey annotation must be on getter method only.
+referenceValidator.not.string=Remote key must be String.
Index: src/main/java/com/sun/enterprise/config/serverbeans/customvalidators/ReferenceConstraint.java
===================================================================
--- src/main/java/com/sun/enterprise/config/serverbeans/customvalidators/ReferenceConstraint.java (revision 0)
+++ src/main/java/com/sun/enterprise/config/serverbeans/customvalidators/ReferenceConstraint.java (working copy)
@@ -0,0 +1,88 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2010-2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.enterprise.config.serverbeans.customvalidators;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+
+/** Annotated {@code ConfigBeanProxy} class contains at least one {@code String}
+ * field, which value must point to key attribute of some other existing
+ * {@code ConfigBeanProxy} instance.
+ * Use {@link ReferenceConstraint.RemoteKey} annotation on appropriate getters
+ * to define such fields.
+ * This constrain is supported for {@code ConfigBeanProxy} only.
+ *
+ * @author Martin Mares
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+@Constraint(validatedBy = ReferenceValidator.class)
+public @interface ReferenceConstraint {
+ String message() default "Invalid reference in provided configuration.";
+ Class>[] groups() default {};
+ Class extends Payload>[] payload() default {};
+
+ /** In GlassFish a lot of configurations are made in batch and its references
+ * could not be fulfilled during creation process.
+ */
+ boolean skipDuringCreation();
+
+ /** This annotation get sense only on getter method and in combination with
+ * {@link ReferenceConstraint} annotation on the class.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ @Documented
+ public @interface RemoteKey {
+ String message() default "";
+ /** Type of {@code ConfigBeanProxy} where this remote key points to.
+ */
+ Class extends ConfigBeanProxy> type();
+ }
+}
Index: src/main/java/com/sun/enterprise/config/serverbeans/customvalidators/ReferenceValidator.java
===================================================================
--- src/main/java/com/sun/enterprise/config/serverbeans/customvalidators/ReferenceValidator.java (revision 0)
+++ src/main/java/com/sun/enterprise/config/serverbeans/customvalidators/ReferenceValidator.java (working copy)
@@ -0,0 +1,159 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.enterprise.config.serverbeans.customvalidators;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.logging.LogDomains;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.logging.Logger;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.UnexpectedTypeException;
+import org.jvnet.hk2.component.Habitat;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.Dom;
+
+/**
+ * @author Martin Mares
+ */
+public class ReferenceValidator implements ConstraintValidator {
+
+ class RemoteKeyInfo {
+ final Method method;
+ final Class sourceClass;
+ final ReferenceConstraint.RemoteKey annotation;
+ public RemoteKeyInfo(Method method, Class sourceClass, ReferenceConstraint.RemoteKey annotation) {
+ this.method = method;
+ this.sourceClass = sourceClass;
+ this.annotation = annotation;
+ }
+ }
+
+ static final Logger logger = LogDomains.getLogger(ConfigRefValidator.class, LogDomains.ADMIN_LOGGER);
+ static final LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ReferenceValidator.class);
+
+ private ReferenceConstraint rc;
+
+ @Override
+ public void initialize(ReferenceConstraint rc) {
+ this.rc = rc;
+ }
+
+ @Override
+ public boolean isValid(ConfigBeanProxy config, ConstraintValidatorContext cvc) throws UnexpectedTypeException {
+ if (config == null) {
+ return true;
+ }
+ Dom dom = Dom.unwrap(config);
+ if (rc.skipDuringCreation() && dom.getKey() == null) {
+ return true; //During creation the coresponding DOM is not fully loaded.
+ }
+ Collection remoteKeys = findRemoteKeys(config);
+ if (remoteKeys != null && !remoteKeys.isEmpty()) {
+ Habitat habitat = dom.getHabitat();
+ boolean result = true;
+ boolean disableGlobalMessage = true;
+ for (RemoteKeyInfo remoteKeyInfo : remoteKeys) {
+ if (remoteKeyInfo.method.getParameterTypes().length > 0) {
+ throw new UnexpectedTypeException(localStrings.getLocalString("referenceValidator.not.getter",
+ "ReferenceConstraint annotaion must be on getter method only."));
+ }
+ try {
+ Object value = remoteKeyInfo.method.invoke(config);
+ if (value instanceof String) {
+ String key = (String) value;
+ ConfigBeanProxy component = habitat.getComponent(remoteKeyInfo.annotation.type(), key);
+ if (component == null) {
+ result = false;
+ if (remoteKeyInfo.annotation.message().isEmpty()) {
+ disableGlobalMessage = false;
+ } else {
+ cvc.buildConstraintViolationWithTemplate(remoteKeyInfo.annotation.message())
+ .addNode(Dom.convertName(remoteKeyInfo.method.getName()))
+ .addConstraintViolation();
+ }
+ }
+ } else {
+ throw new UnexpectedTypeException(localStrings.getLocalString("referenceValidator.not.string",
+ "Remote key must be String."));
+ }
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+ if (!result && disableGlobalMessage) {
+ cvc.disableDefaultConstraintViolation();
+ }
+ return result;
+ }
+ return true;
+ }
+
+ private Collection findRemoteKeys(Object o) {
+ Collection result = new ArrayList();
+ if (o == null) {
+ return result;
+ }
+ findRemoteKeys(o.getClass(), result);
+ return result;
+ }
+
+ private void findRemoteKeys(Class c, Collection result) {
+ Method[] methods = c.getMethods();
+ for (Method method : methods) {
+ ReferenceConstraint.RemoteKey annotation = method.getAnnotation(ReferenceConstraint.RemoteKey.class);
+ if (annotation != null) {
+ result.add(new RemoteKeyInfo(method, c, annotation));
+ }
+ }
+ Class superclass = c.getSuperclass();
+ if (superclass != null) {
+ findRemoteKeys(superclass, result);
+ }
+ Class[] interfaces = c.getInterfaces();
+ for (Class iface : interfaces) {
+ findRemoteKeys(iface, result);
+ }
+ }
+
+}
Index: src/main/java/com/sun/enterprise/config/serverbeans/JdbcResource.java
===================================================================
--- src/main/java/com/sun/enterprise/config/serverbeans/JdbcResource.java (revision 51804)
+++ src/main/java/com/sun/enterprise/config/serverbeans/JdbcResource.java (working copy)
@@ -40,6 +40,7 @@
package com.sun.enterprise.config.serverbeans;
+import com.sun.enterprise.config.serverbeans.customvalidators.ReferenceConstraint;
import com.sun.enterprise.config.serverbeans.customvalidators.ResourcePoolReferenceConstraint;
import org.jvnet.hk2.config.Attribute;
import org.jvnet.hk2.config.ConfigBeanProxy;
@@ -77,7 +78,8 @@
@RestRedirect(opType = RestRedirect.OpType.POST, commandName = "create-jdbc-resource"),
@RestRedirect(opType = RestRedirect.OpType.DELETE, commandName = "delete-jdbc-resource")
})
-@ResourcePoolReferenceConstraint(message="{resource.invalid}", payload=JdbcResource.class)
+//@ResourcePoolReferenceConstraint(message="{resource.invalid}", payload=JdbcResource.class)
+@ReferenceConstraint(skipDuringCreation=true, payload=JdbcResource.class)
public interface JdbcResource extends ConfigBeanProxy, Injectable, Resource,
PropertyBag, BindableResource, Payload {
@@ -90,6 +92,7 @@
@Attribute
@NotNull
@Param(name="connectionpoolid")
+ @ReferenceConstraint.RemoteKey(message="{resourceref.invalid.poolname}", type=JdbcConnectionPool.class)
String getPoolName();
/**
Index: src/main/java/com/sun/enterprise/config/serverbeans/LocalStrings.properties
===================================================================
--- src/main/java/com/sun/enterprise/config/serverbeans/LocalStrings.properties (revision 51804)
+++ src/main/java/com/sun/enterprise/config/serverbeans/LocalStrings.properties (working copy)
@@ -126,6 +126,7 @@
resourcepool.invalid.name.key=Invalid pool name. A pool name must start with a letter, number or underscore and may contain only letters, numbers and these special characters: hyphen, underscore, period, slash, semicolon, colon, hash. Pool name must not contain any spaces.
resourcename.invalid.character=resource name cannot contain ':' character
resource.invalid=Invalid pool name. Check whether the pool exists.
+resourceref.invalid.poolname=Invalid pool name! Check whether the pool exists.
SecureAdminPrincipalResolver.configTypeNotNamed=Config type {0} must extend {1} but does not
SecureAdminPrincipalResolver.target_object_not_found=Cannot find a {0} with a name {1}
Index: src/test/java/com/sun/enterprise/configapi/tests/validation/ReferenceConstrainTest.java
===================================================================
--- src/test/java/com/sun/enterprise/configapi/tests/validation/ReferenceConstrainTest.java (revision 0)
+++ src/test/java/com/sun/enterprise/configapi/tests/validation/ReferenceConstrainTest.java (working copy)
@@ -0,0 +1,152 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.enterprise.configapi.tests.validation;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.JdbcResource;
+import com.sun.enterprise.configapi.tests.ConfigApiTest;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import javax.validation.ConstraintViolationException;
+import org.junit.Test;
+import org.junit.Before;
+import org.jvnet.hk2.component.Habitat;
+import org.glassfish.tests.utils.Utils;
+import org.jvnet.hk2.config.ConfigBean;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.TransactionFailure;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author mmares
+ */
+public class ReferenceConstrainTest extends ConfigApiTest {
+
+// private Logger logger = Logger.getLogger(ReferenceConstrainTest.class.getName());
+ private Habitat habitat;
+
+ @Override
+ public String getFileName() {
+ return "DomainTest";
+ }
+
+ @Override
+ public Habitat getHabitat() {
+ return habitat;
+ }
+
+ private ConstraintViolationException findConstrViolation(Throwable thr) {
+ if (thr == null) {
+ return null;
+ }
+ if (thr instanceof ConstraintViolationException) {
+ return (ConstraintViolationException) thr;
+ }
+ return findConstrViolation(thr.getCause());
+ }
+
+ @Before
+ public void createNewHabitat() {
+ this.habitat = Utils.getNewHabitat(this);
+ }
+
+ @Test
+ public void doChangeToValidPool() throws TransactionFailure {
+ Domain domain = habitat.getComponent(Domain.class);
+ //Find JdbcResource to chenge its values
+ Iterator iterator = domain.getResources().getResources(JdbcResource.class).iterator();
+ JdbcResource jdbc = null;
+ while (iterator.hasNext()) {
+ JdbcResource res = iterator.next();
+ if ("__TimerPool".equals(res.getPoolName())) {
+ jdbc = res;
+ break;
+ }
+ }
+ assertNotNull(jdbc);
+ ConfigBean poolConfig = (ConfigBean) ConfigBean.unwrap(jdbc);
+ Map> changes = new HashMap>();
+ Map configChanges = new HashMap();
+ configChanges.put("pool-name", "DerbyPool");
+ changes.put(poolConfig, configChanges);
+ try {
+ ConfigSupport cs = getHabitat().getComponent(ConfigSupport.class);
+ cs.apply(changes);
+ assertTrue("Valid change, must reach this point", true);
+ } catch (TransactionFailure tf) {
+ //assertNotNull(findConstrViolation(tf));
+ }
+ }
+
+ @Test
+ public void doChangeToInValidPool() throws TransactionFailure {
+ Domain domain = habitat.getComponent(Domain.class);
+ //Find JdbcResource to chenge its values
+ Iterator iterator = domain.getResources().getResources(JdbcResource.class).iterator();
+ JdbcResource jdbc = null;
+ while (iterator.hasNext()) {
+ JdbcResource res = iterator.next();
+ if ("__TimerPool".equals(res.getPoolName())) {
+ jdbc = res;
+ break;
+ }
+ }
+ assertNotNull(jdbc);
+ ConfigBean poolConfig = (ConfigBean) ConfigBean.unwrap(jdbc);
+ Map> changes = new HashMap>();
+ Map configChanges = new HashMap();
+ configChanges.put("pool-name", "WrongPointer");
+ changes.put(poolConfig, configChanges);
+ try {
+ ConfigSupport cs = getHabitat().getComponent(ConfigSupport.class);
+ cs.apply(changes);
+ assertFalse("Can not reach this point", true);
+ } catch (TransactionFailure tf) {
+ ConstraintViolationException cv = findConstrViolation(tf);
+// cv.printStackTrace(System.out);
+ assertNotNull(cv);
+ }
+ }
+
+}
\ No newline at end of file