| /* |
| * 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.geode.distributed.internal.membership; |
| |
| import static com.tngtech.archunit.base.DescribedPredicate.not; |
| import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo; |
| import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAPackage; |
| import static com.tngtech.archunit.core.domain.JavaClass.Predicates.type; |
| import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; |
| |
| import com.tngtech.archunit.junit.AnalyzeClasses; |
| import com.tngtech.archunit.junit.ArchIgnore; |
| import com.tngtech.archunit.junit.ArchTest; |
| import com.tngtech.archunit.junit.ArchUnitRunner; |
| import com.tngtech.archunit.lang.ArchRule; |
| import org.junit.runner.RunWith; |
| |
| import org.apache.geode.CancelCriterion; |
| import org.apache.geode.DataSerializer; |
| import org.apache.geode.GemFireException; |
| import org.apache.geode.InternalGemFireError; |
| import org.apache.geode.SystemFailure; |
| import org.apache.geode.cache.GemFireCache; |
| import org.apache.geode.distributed.DistributedMember; |
| import org.apache.geode.distributed.DistributedSystem; |
| import org.apache.geode.distributed.DurableClientAttributes; |
| import org.apache.geode.distributed.Locator; |
| import org.apache.geode.distributed.Role; |
| import org.apache.geode.distributed.internal.ClusterDistributionManager; |
| import org.apache.geode.distributed.internal.DMStats; |
| import org.apache.geode.distributed.internal.DistributionConfig; |
| import org.apache.geode.distributed.internal.DistributionConfigImpl; |
| import org.apache.geode.distributed.internal.DistributionManager; |
| import org.apache.geode.distributed.internal.DistributionMessage; |
| import org.apache.geode.distributed.internal.FlowControlParams; |
| import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService; |
| import org.apache.geode.distributed.internal.InternalDistributedSystem; |
| import org.apache.geode.distributed.internal.InternalLocator; |
| import org.apache.geode.distributed.internal.LocatorStats; |
| import org.apache.geode.distributed.internal.OverflowQueueWithDMStats; |
| import org.apache.geode.distributed.internal.ServerLocation; |
| import org.apache.geode.distributed.internal.SizeableRunnable; |
| import org.apache.geode.distributed.internal.direct.DirectChannel; |
| import org.apache.geode.distributed.internal.direct.DirectChannelListener; |
| import org.apache.geode.distributed.internal.tcpserver.TcpClient; |
| import org.apache.geode.distributed.internal.tcpserver.TcpHandler; |
| import org.apache.geode.distributed.internal.tcpserver.TcpServer; |
| import org.apache.geode.internal.Assert; |
| import org.apache.geode.internal.ClassPathLoader; |
| import org.apache.geode.internal.ConnectionWatcher; |
| import org.apache.geode.internal.DataSerializableFixedID; |
| import org.apache.geode.internal.HeapDataOutputStream; |
| import org.apache.geode.internal.InternalDataSerializer; |
| import org.apache.geode.internal.OSProcess; |
| import org.apache.geode.internal.SystemTimer; |
| import org.apache.geode.internal.Version; |
| import org.apache.geode.internal.VersionedDataInputStream; |
| import org.apache.geode.internal.VersionedObjectInput; |
| import org.apache.geode.internal.admin.remote.DistributionLocatorId; |
| import org.apache.geode.internal.admin.remote.RemoteTransportConfig; |
| import org.apache.geode.internal.alerting.AlertingAction; |
| import org.apache.geode.internal.cache.DirectReplyMessage; |
| import org.apache.geode.internal.cache.GemFireCacheImpl; |
| import org.apache.geode.internal.cache.InternalCache; |
| import org.apache.geode.internal.concurrent.ConcurrentHashSet; |
| import org.apache.geode.internal.logging.LogService; |
| import org.apache.geode.internal.logging.LoggingExecutors; |
| import org.apache.geode.internal.logging.LoggingThread; |
| import org.apache.geode.internal.logging.log4j.AlertAppender; |
| import org.apache.geode.internal.logging.log4j.LogMarker; |
| import org.apache.geode.internal.net.SocketCreator; |
| import org.apache.geode.internal.net.SocketCreatorFactory; |
| import org.apache.geode.internal.security.SecurableCommunicationChannel; |
| import org.apache.geode.internal.tcp.ConnectExceptions; |
| import org.apache.geode.internal.util.Breadcrumbs; |
| import org.apache.geode.internal.util.JavaWorkarounds; |
| |
| @RunWith(ArchUnitRunner.class) |
| @AnalyzeClasses(packages = "org.apache.geode.distributed.internal.membership..") |
| public class MembershipDependenciesJUnitTest { |
| |
| /* |
| * This test verifies that the membership component (which is currently made up of classes |
| * inside the geode-core module, but which may someday reside in a separate module) |
| * depends only on packages within itself (within the membership component) or packages |
| * outside apache.geode. |
| * |
| * For purposes of this test, classes in the membership...adapter package are not considered. |
| * They will eventually become part of geode-core. |
| * |
| * While this rule is ignored, comment-out the ignore annotation to run it periodically to get |
| * the current count of deviations. |
| */ |
| // TODO: remove ignore once membershipDoesntDependOnCoreProvisional matches this rule exactly |
| @ArchIgnore |
| @ArchTest |
| public static final ArchRule membershipDoesntDependOnCore = classes() |
| .that() |
| .resideInAPackage("org.apache.geode.distributed.internal.membership..") |
| .and() |
| .resideOutsideOfPackage("org.apache.geode.distributed.internal.membership.adapter..") |
| .should() |
| .onlyDependOnClassesThat( |
| resideInAPackage("org.apache.geode.distributed.internal.membership..") |
| .or(not(resideInAPackage("org.apache.geode..")))); |
| |
| /* |
| * This test is a work-in-progress. It starts from the membershipDoesntDependOnCore rule |
| * and adds deviations. Each deviation has a comment like TODO:... |
| * Those deviations comprise a to do list for the membership team as it modularizes |
| * the membership component--severing its dependency on the geode-core component. |
| */ |
| @ArchTest |
| public static final ArchRule membershipDoesntDependOnCoreProvisional = classes() |
| .that() |
| .resideInAPackage("org.apache.geode.distributed.internal.membership..") |
| .and() |
| .resideOutsideOfPackage("org.apache.geode.distributed.internal.membership.adapter..") |
| .and() |
| |
| // TODO: InternalDistributedMember needs to move out of the package |
| .areNotAssignableFrom(InternalDistributedMember.class) |
| |
| |
| .should() |
| .onlyDependOnClassesThat( |
| resideInAPackage("org.apache.geode.distributed.internal.membership..") |
| |
| .or(not(resideInAPackage("org.apache.geode.."))) |
| |
| // TODO: Create a new stats interface for membership |
| .or(assignableTo(DMStats.class)) |
| .or(type(LocatorStats.class)) |
| .or(type(OverflowQueueWithDMStats.class)) |
| |
| // TODO: Figure out what to do with exceptions |
| .or(assignableTo(GemFireException.class)) |
| .or(type(InternalGemFireError.class)) |
| .or(type(ConnectExceptions.class)) |
| |
| // TODO: Serialization needs to become its own module |
| .or(type(DataSerializer.class)) |
| .or(type(DataSerializableFixedID.class)) |
| .or(type(InternalDataSerializer.class)) |
| .or(type(Version.class)) |
| .or(type(Version[].class)) // ArchUnit needs the array type to be explicitly mentioned |
| .or(type(VersionedObjectInput.class)) |
| .or(type(HeapDataOutputStream.class)) |
| .or(type(VersionedDataInputStream.class)) |
| |
| // TODO: Figure out what to do with messaging |
| // Membership messages don't need to extend DistributionMessage |
| .or(assignableTo(DistributionMessage.class)) |
| .or(assignableTo(DirectReplyMessage.class)) |
| |
| // TODO: Membership needs its own config object |
| .or(type(DistributionConfig.class)) |
| .or(type(DistributionConfigImpl.class)) |
| .or(type(RemoteTransportConfig.class)) |
| .or(type(FlowControlParams.class)) |
| |
| |
| // TODO: Break dependency on geode logger |
| .or(type(LogService.class)) |
| .or(assignableTo(LoggingThread.class)) |
| .or(type(LoggingExecutors.class)) |
| .or(type(LogMarker.class)) |
| .or(type(AlertAppender.class)) |
| |
| // TODO |
| .or(type(SystemFailure.class)) |
| |
| // TODO: Break dependency on Role |
| .or(assignableTo(Role.class)) |
| |
| // TODO: Break dependency on SystemTimerTask |
| .or(assignableTo(SystemTimer.SystemTimerTask.class)) |
| .or(type(SystemTimer.class)) |
| |
| // TODO: Break dependency on SizeableRunnable |
| .or(assignableTo(SizeableRunnable.class)) |
| |
| // TODO: Break dependency on DirectChannelListener (and its getDM method!) |
| .or(assignableTo(DirectChannelListener.class)) |
| |
| // TODO: This and TCP conduit be moved inside membership. |
| // Do we even need this class since it is just forwarding to TCPConduit? |
| .or(type(DirectChannel.class)) |
| |
| // TODO: Break dependency on geode DurableClientAttributes |
| .or(type(DurableClientAttributes.class)) |
| |
| // TODO |
| .or(assignableTo(CancelCriterion.class)) |
| |
| // TODO |
| .or(assignableTo(ConnectionWatcher.class)) |
| |
| // TODO: |
| .or(type(SocketCreator.class)) |
| .or(type(SocketCreatorFactory.class)) |
| |
| // TODO: |
| .or(type(Assert.class)) |
| |
| // TODO: break dependencies on locator-related classes |
| .or(type(Locator.class)) |
| .or(type(TcpHandler.class)) |
| .or(type(TcpClient.class)) |
| .or(type(TcpServer.class)) |
| .or(type(ServerLocation.class)) |
| .or(type(InternalLocator.class)) |
| .or(type(DistributionLocatorId.class)) |
| .or(type(InternalConfigurationPersistenceService.class)) |
| |
| // TODO: Mt. Olympus (G*D objects live here) |
| .or(type(DistributionManager.class)) |
| .or(type(InternalDistributedSystem.class)) |
| .or(type(DistributedSystem.class)) |
| .or(type(GemFireCache.class)) |
| .or(type(GemFireCacheImpl.class)) |
| .or(type(InternalCache.class)) |
| .or(type(ClusterDistributionManager.class)) |
| |
| // TODO: break dependency on internal.security |
| .or(type(SecurableCommunicationChannel.class)) |
| |
| // TODO: |
| .or(type(DistributedMember.class)) |
| |
| // TODO: |
| .or(type(JavaWorkarounds.class)) |
| |
| // TODO: |
| .or(type(ConcurrentHashSet.class)) |
| |
| // TODO: |
| .or(type(OSProcess.class)) |
| |
| // TODO: |
| .or(type(ClassPathLoader.class)) |
| |
| // TODO: |
| .or(type(AlertingAction.class)) |
| |
| // TODO: |
| .or(type(Breadcrumbs.class)) |
| |
| ); |
| |
| } |