Skip to content

Commit

Permalink
Support compatibility (sofastack#1221)
Browse files Browse the repository at this point in the history
  • Loading branch information
HzjNeverStop authored and 致节 committed Aug 14, 2023
1 parent c221873 commit 856d0b5
Show file tree
Hide file tree
Showing 15 changed files with 767 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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 com.alipay.sofa.boot.compatibility;

import org.springframework.core.env.Environment;

import java.util.Collection;

/**
* Abstract class for {@link AbstractSwitchableCompatibilityVerifier} to verify jar compatibility.
*
* @author huzijie
* @version AbstractJarVersionVerifier.java, v 0.1 2023年08月03日 5:14 PM huzijie Exp $
*/
public abstract class AbstractJarVersionVerifier extends AbstractSwitchableCompatibilityVerifier {

public AbstractJarVersionVerifier(Environment environment) {
super(environment);
}

@Override
public CompatibilityPredicate compatibilityPredicate() {
return () -> {
Collection<CompatibilityPredicate> compatibilityPredicates = getJarCompatibilityPredicates();
if (compatibilityPredicates == null) {
return true;
}
return compatibilityPredicates.stream().allMatch(CompatibilityPredicate::isCompatible);
};
}

@Override
public String errorDescription() {
return String.format("SOFABoot is not compatible with jar [%s] for current version.",
name());
}

@Override
public String action() {
return String.format(
"Change [%s] to appropriate version,"
+ "you can visit this doc [%s] and find an appropriate version,"
+ "If you want to disable this check, just set the property [%s=false].",
name(), doc(), this.enableKey);
}

public abstract Collection<CompatibilityPredicate> getJarCompatibilityPredicates();

public abstract String name();

public abstract String doc();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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 com.alipay.sofa.boot.compatibility;

import org.springframework.core.env.Environment;

/**
* Abstract class for {@link CompatibilityVerifier} to support switch.
*
* @author huzijie
* @version AbstractSwitchableCompatibilityVerifier.java, v 0.1 2023年08月03日 6:10 PM huzijie Exp $
*/
public abstract class AbstractSwitchableCompatibilityVerifier implements CompatibilityVerifier {

private static final String ENABLE_KEY_FORMAT = "sofa.boot.compatibility-verifier.%s.enabled";

protected final Environment environment;

protected String enableKey;

public AbstractSwitchableCompatibilityVerifier(Environment environment) {
this.environment = environment;
}

@Override
public VerificationResult verify() {
this.enableKey = String.format(ENABLE_KEY_FORMAT, enableKey());
if (!Boolean.parseBoolean(environment.getProperty(enableKey, "true"))) {
return VerificationResult.compatible();
}

CompatibilityPredicate compatibilityPredicate = compatibilityPredicate();
boolean matches = compatibilityPredicate.isCompatible();
if (matches) {
return VerificationResult.compatible();
}
return VerificationResult.notCompatible(errorDescription(), action());
}

public abstract CompatibilityPredicate compatibilityPredicate();

public abstract String errorDescription();

public abstract String action();

public abstract String enableKey();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 com.alipay.sofa.boot.compatibility;

import java.util.Arrays;
import java.util.List;

/**
* Exception for not compatibility met.
*
* @author huzijie
* @version CompatibilityNotMetException.java, v 0.1 2023年08月03日 4:40 PM huzijie Exp $
*/
public class CompatibilityNotMetException extends RuntimeException {

final List<VerificationResult> results;

CompatibilityNotMetException(List<VerificationResult> results, String errorMessage) {
super("Compatibility checks have failed: " + errorMessage);
this.results = results;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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 com.alipay.sofa.boot.compatibility;

/**
* Interface for Predicate compatibility verify result, for form spring cloud.
*
* @author huzijie
* @version CompatibilityPredicate.java, v 0.1 2023年08月03日 4:35 PM huzijie Exp $
*/
public interface CompatibilityPredicate {

/**
* whether is compatible
* @return compatible result
*/
boolean isCompatible();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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 com.alipay.sofa.boot.compatibility;

/**
* Interface for compatibility verifier, for form spring cloud.
*
* @author huzijie
* @version CompatibilityVerifier.java, v 0.1 2023年08月03日 4:08 PM huzijie Exp $
*/
public interface CompatibilityVerifier {

/**
* verify compatibility
* @return verify result
*/
VerificationResult verify();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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 com.alipay.sofa.boot.compatibility;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.SpringFactoriesLoader;

import java.util.List;

/**
* Implements for {@link ApplicationContextInitializer} to verify compatibilities.
*
* @author huzijie
* @version CompatibilityVerifierApplicationContextInitializer.java, v 0.1 2023年08月03日 4:44 PM huzijie Exp $
*/
public class CompatibilityVerifierApplicationContextInitializer
implements
ApplicationContextInitializer<ConfigurableApplicationContext> {

public static final String COMPATIBILITY_VERIFIER_ENABLED = "sofa.boot.compatibility-verifier.enabled";

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
Environment environment = applicationContext.getEnvironment();
if (!Boolean.parseBoolean(environment.getProperty(COMPATIBILITY_VERIFIER_ENABLED, "true"))) {
Logger logger = LoggerFactory.getLogger(CompatibilityVerifierApplicationContextInitializer.class);
logger.info("Skip SOFABoot compatibility Verifier");
return;
}

// Load all CompatibilityVerifier and verify.
CompositeCompatibilityVerifier compositeCompatibilityVerifier = new CompositeCompatibilityVerifier(
getCompatibilityVerifierInstances(environment));
compositeCompatibilityVerifier.verifyCompatibilities();
}

private List<CompatibilityVerifier> getCompatibilityVerifierInstances(Environment environment) {

SpringFactoriesLoader.ArgumentResolver argumentResolver = SpringFactoriesLoader.ArgumentResolver
.of(Environment.class, environment);
SpringFactoriesLoader springFactoriesLoader = SpringFactoriesLoader.forDefaultResourceLocation();
// Use names and ensure unique to protect against duplicates
List<CompatibilityVerifier> instances = springFactoriesLoader.load(
CompatibilityVerifier.class, argumentResolver);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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 com.alipay.sofa.boot.compatibility;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
* Composite compatibility verifier.
*
* @author huzijie
* @version CompositeCompatibilityVerifier.java, v 0.1 2023年08月03日 4:40 PM huzijie Exp $
*/
public class CompositeCompatibilityVerifier {

private final List<CompatibilityVerifier> verifiers;

public CompositeCompatibilityVerifier(List<CompatibilityVerifier> verifiers) {
this.verifiers = verifiers;
}

public void verifyCompatibilities() {
List<VerificationResult> errors = verifierErrors();
if (errors.isEmpty()) {
return;
}
String errorMessage = errors.stream().map(VerificationResult::toErrorMessage).toList().toString();
throw new CompatibilityNotMetException(errors, errorMessage);
}

private List<VerificationResult> verifierErrors() {
List<VerificationResult> errors = new ArrayList<>();
for (CompatibilityVerifier verifier : this.verifiers) {
VerificationResult result = verifier.verify();
if (result.isNotCompatible()) {
errors.add(result);
}
}
return errors;
}
}
Loading

0 comments on commit 856d0b5

Please sign in to comment.