blob: 2ff895522e11dbb73af8c0c99a84615483df5776 [file] [log] [blame]
/*
* Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
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 jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.UnexpectedTypeException;
import org.glassfish.hk2.api.ServiceLocator;
import org.jvnet.hk2.config.ConfigBeanProxy;
import org.jvnet.hk2.config.Dom;
/**
* @author Martin Mares
*/
public class ReferenceValidator implements ConstraintValidator<ReferenceConstraint, ConfigBeanProxy> {
static class RemoteKeyInfo {
final Method method;
final ReferenceConstraint.RemoteKey annotation;
public RemoteKeyInfo(Method method, ReferenceConstraint.RemoteKey annotation) {
this.method = method;
this.annotation = annotation;
}
}
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<RemoteKeyInfo> remoteKeys = findRemoteKeys(config);
if (!remoteKeys.isEmpty()) {
ServiceLocator 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",
"The RemoteKey annotation must be on a getter method."));
}
try {
Object value = remoteKeyInfo.method.invoke(config);
if (value instanceof String) {
String key = (String) value;
ConfigBeanProxy component = habitat.getService(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",
"The RemoteKey annotation must identify a method that returns a String."));
}
} catch (Exception ex) {
return false;
}
}
if (!result && disableGlobalMessage) {
cvc.disableDefaultConstraintViolation();
}
return result;
}
return true;
}
private Collection<RemoteKeyInfo> findRemoteKeys(Object o) {
Collection<RemoteKeyInfo> result = new ArrayList<RemoteKeyInfo>();
if (o == null) {
return result;
}
findRemoteKeys(o.getClass(), result);
return result;
}
private void findRemoteKeys(Class c, Collection<RemoteKeyInfo> 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, annotation));
}
}
Class superclass = c.getSuperclass();
if (superclass != null) {
findRemoteKeys(superclass, result);
}
Class[] interfaces = c.getInterfaces();
for (Class iface : interfaces) {
findRemoteKeys(iface, result);
}
}
}