Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * JBoss, Home of Professional Open Source.
   * Copyright 2011, Red Hat, Inc., and individual contributors
   * as indicated by the @author tags. See the copyright.txt file in the
   * distribution for a full listing of individual contributors.
   *
   * This is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as
   * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
 
 package org.jboss.as.host.controller;
 
 import static java.security.AccessController.doPrivileged;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DOMAIN_MODEL;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.EXTENSION;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILURE_DESCRIPTION;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OPERATION_HEADERS;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS;
 import static org.jboss.as.host.controller.HostControllerLogger.ROOT_LOGGER;
 import static org.jboss.as.host.controller.HostControllerMessages.MESSAGES;
 
 import java.io.File;
 import java.net.URI;
 import java.util.List;
 
 
Establishes the connection from a slave org.jboss.as.domain.controller.DomainController to the master org.jboss.as.domain.controller.DomainController

Author(s):
Kabir Khan
    public static final String DOMAIN_CONNECTION_ID = "domain-connection-id";
    private static final int CONNECTION_TIMEOUT_DEFAULT = 30000;
    private static final String CONNECTION_TIMEOUT_PROPERTY = "jboss.host.domain.connection.timeout";
    private static final ModelNode APPLY_EXTENSIONS = new ModelNode();
    private static final ModelNode APPLY_DOMAIN_MODEL = new ModelNode();
    static {
        .get("execute-for-coordinator").set(true);
        .protect();
        //FIXME this makes the op work after boot (i.e. slave connects to restarted master), but does not make the slave resync the servers
        .get("execute-for-coordinator").set(true);
        .protect();
    }
    private final ExtensionRegistry extensionRegistry;
    private final ModelController controller;
    private final ProductConfig productConfig;
    private final LocalHostControllerInfo localHostInfo;
    private final DomainController domainController;
    private final RunningMode runningMode;

    
Used to invoke ModelController ops on the master
    private volatile ModelControllerClient masterProxy;
    private final FutureClient futureClient = new FutureClient();
    private final InjectedValue<EndpointendpointInjector = new InjectedValue<Endpoint>();
    private final ExecutorService executor;
    private volatile RemoteDomainConnection connection;
    private RemoteDomainConnectionService(final ModelController controllerfinal ExtensionRegistry extensionRegistry,
                                          final LocalHostControllerInfo localHostControllerInfofinal ProductConfig productConfig,
                                          final RemoteFileRepository remoteFileRepository,
                                          final IgnoredDomainResourceRegistry ignoredDomainResourceRegistry,
                                          final HostControllerRegistrationHandler.OperationExecutor operationExecutor,
                                          final DomainController domainController,
                                          final HostControllerEnvironment hostControllerEnvironment,
                                          final ExecutorService executor,
                                          final RunningMode runningMode){
        this. = controller;
        this. = extensionRegistry;
        this. = productConfig;
        this. = localHostControllerInfo;
        this. = remoteFileRepository;
        this. = ignoredDomainResourceRegistry;
        this. = operationExecutor;
        this. = domainController;
        this. = hostControllerEnvironment;
        this. = executor;
        this. = runningMode;
    }
    public static Future<MasterDomainControllerClientinstall(final ServiceTarget serviceTargetfinal ModelController controllerfinal ExtensionRegistry extensionRegistry,
                                                               final LocalHostControllerInfo localHostControllerInfofinal ProductConfig productConfig,
                                                               final String securityRealmfinal RemoteFileRepository remoteFileRepository,
                                                               final IgnoredDomainResourceRegistry ignoredDomainResourceRegistry,
                                                               final HostControllerRegistrationHandler.OperationExecutor operationExecutor,
                                                               final DomainController domainController,
                                                               final HostControllerEnvironment hostControllerEnvironment,
                                                               final ExecutorService executor,
                                                               final RunningMode currentRunningMode) {
        RemoteDomainConnectionService service = new RemoteDomainConnectionService(controllerextensionRegistrylocalHostControllerInfo,
                productConfigremoteFileRepositoryignoredDomainResourceRegistryoperationExecutordomainController,
                hostControllerEnvironmentexecutorcurrentRunningMode);
                .addDependency(.Endpoint.classservice.endpointInjector)
                .addDependency(.ServerInventory.classservice.serverInventoryInjector)
                .setInitialMode(..);
        if (securityRealm != null) {
            SecurityRealm.ServiceUtil.addDependency(builderservice.securityRealmInjectorsecurityRealmfalse);
        }
        builder.install();
        return service.futureClient;
    }

    
    public synchronized void register() throws IOException {
        boolean connected = false;
        // Loop through discovery options
        for (Iterator<DiscoveryOptioni = discoveryOptions.iterator(); i.hasNext(); ) {
           DiscoveryOption discoveryOption = i.next();
           final long timeout = ;
           final long endTime = System.currentTimeMillis() + timeout;
           int retries = 0;
           URI masterURI = null;
           try {
               // Determine the remote DC host and port to use
               discoveryOption.discover();
               String host = discoveryOption.getRemoteDomainControllerHost();
               int port = discoveryOption.getRemoteDomainControllerPort();
               masterURI = new URI("remote://" + NetworkUtils.formatPossibleIpv6Address(host) + ":" + port);
               .setUri(masterURI);
               while (!connected) {
                   try {
                       // Try to connect to the domain controller
                       .connect();
                       connected = true;
                   } catch (IOException e) {
                       // If the cause is one of the irrecoverable ones, unwrap and throw it on
                       rethrowIrrecoverableConnectionFailures(e);
                       // Something else; we can retry if time remains
                       ..cannotConnect(masterURIe);
                       if (System.currentTimeMillis() > endTime) {
                           throw .connectionToMasterTimeout(eretriestimeout);
                       }
                       try {
                           ..wait(retries);
                           retries++;
                       } catch (InterruptedException ie) {
                           Thread.currentThread().interrupt();
                           throw .connectionToMasterInterrupted();
                       }
                   }
               }
               ..connectedToMaster(masterURI);
               // Setup the transaction protocol handler
               // Use the existing channel strategy
                = ExistingChannelModelControllerClient.createAndAdd();
                = new TransactionalDomainControllerClient();
               break;
           } catch (Exception e) {
               boolean moreOptions = i.hasNext();
               logConnectionException(masterURIdiscoveryOptionmoreOptionse);
               if (!moreOptions) {
                   throw .discoveryOptionsFailureUnableToConnect(e);
               }
           }
        }
    }

    
    public synchronized void unregister() {
        StreamUtils.safeClose();
    }
    @Override
    public void fetchDomainWideConfiguration() {
        try {
            //TODO implement fetchDomainWideConfiguration
            throw new UnsupportedOperationException();
        } finally {
            StreamUtils.safeClose();
        }
    }

    
    public synchronized HostFileRepository getRemoteFileRepository() {
        return ;
    }
    @Override
    public ModelNode execute(ModelNode operationthrows IOException {
        return execute(operation.);
    }
    @Override
    public ModelNode execute(Operation operationthrows IOException {
        return .execute(operation.);
    }
    @Override
    public ModelNode execute(ModelNode operationOperationMessageHandler messageHandlerthrows IOException {
        return .execute(operationmessageHandler);
    }
    @Override
    public ModelNode execute(Operation operationOperationMessageHandler messageHandlerthrows IOException {
        return .execute(operationmessageHandler);
    }
    @Override
    public AsyncFuture<ModelNodeexecuteAsync(ModelNode operationOperationMessageHandler messageHandler) {
        return .executeAsync(operationmessageHandler);
    }
    @Override
    public AsyncFuture<ModelNodeexecuteAsync(Operation operationOperationMessageHandler messageHandler) {
        return .executeAsync(operationmessageHandler);
    }
    @Override
    public void pullDownDataForUpdatedServerConfigAndApplyToModel(OperationContext contextString serverNameString serverGroupNameString socketBindingGroupNamethrows OperationFailedException {
        ModelNode op = new ModelNode();
        op.get().setEmptyList();
        op.get().set(IgnoredNonAffectedServerGroupsUtil.createServerConfigInfo(serverNameserverGroupNamesocketBindingGroupName).toModelNode());
        if (domainControllerLock != null) {
            op.get(.).set(domainControllerLock);
        }
        ModelNode result = .executeTransactional(contextop);
        if (result.get().isDefined()) {
            throw new OperationFailedException(result.get().asString());
        }
        ModelNode applyMissingResourcesOp = ApplyMissingDomainModelResourcesHandler.createPulledMissingDataOperation(result.get());
        context.addStep(applyMissingResourcesOpapplyMissingDomainModelResourcesHandler..true);
    }
    @Override
    public void close() throws IOException {
        throw .closeShouldBeManagedByService();
    }

    
    @Override
    public synchronized void start(StartContext contextthrows StartException {
        final RemoteDomainConnection connection;
        final ManagementChannelHandler handler;
        try {
            ThreadFactory scheduledThreadFactory = new JBossThreadFactory(new ThreadGroup("domain-connection-pinger-threads"), .null"%G - %t"nullnulldoPrivileged(GetAccessControlContextAction.getInstance()));
            this. = Executors.newSingleThreadScheduledExecutor(scheduledThreadFactory);
            // Include additional local host information when registering at the DC
            final ModelNode hostInfo = HostInfo.createLocalHostHostInfo(, ReadRootResourceHandler.grabDomainResource().getChildren().iterator().next());
            final OptionMap options = OptionMap.builder().set(., 15000)
                    .set(., 45000)
            // Gather the required information to connect to the remote DC
            final ProtocolChannelClient.Configuration configuration = new ProtocolChannelClient.Configuration();
            // The URI will be set accordingly when looping through discovery options when registering with
            // or reconnecting to the remote DC.
            configuration.setEndpoint(.getValue());
            configuration.setOptionMap(options);
            final SecurityRealm realm = .getOptionalValue();
            // Create the remote domain channel strategy
            connection = new RemoteDomainConnection(.getLocalHostName(), hostInfoconfigurationrealm,
                    .getRemoteDomainControllerUsername(),
                    new RemoteDomainConnection.HostRegistrationCallback() {
                @Override
                public ModelNode resolveSubsystemVersions(ModelNode extensions) {
                    return resolveSubsystems(extensions.asList());
                }
                        @Override
                public boolean applyDomainModel(final List<ModelNodebootOperations) {
                    // Apply the model..
                    return applyRemoteDomainModel(bootOperations);
                }
                @Override
                public void registrationComplete(ManagementChannelHandler handler) {
                    //
                }
            }, );
            // Setup the management channel handler
            handler = connection.getChannelHandler();
        } catch (Exception e) {
            throw new StartException(e);
        } finally {
            .setClient(this);
        }
        this. = connection;
        this. = handler;
    }

    
Resolve the subsystem versions.

Parameters:
extensions the extensions to install
Returns:
the subsystem versions
    private ModelNode resolveSubsystems(final List<ModelNodeextensions) {
        final List<ModelNodebootOperations = new ArrayList<ModelNode>();
        for (final ModelNode extension : extensions) {
            final ModelNode e = new ModelNode();
            e.get("domain-resource-address").add(extension.asString());
            bootOperations.add(e);
        }
        final ModelNode operation = .clone();
        operation.get().set(bootOperations);
        if (!.equals(result.get().asString())) {
        }
        final ModelNode subsystems = new ModelNode();
        for (final ModelNode extension : extensions) {
            .recordSubsystemVersions(extension.asString(), subsystems);
        }
        return subsystems;
    }

    
Apply the remote domain model to the local host controller.

Parameters:
bootOperations the result of the remote read-domain-model op
Returns:
true if the model was applied successfully, false otherwise
    private boolean applyRemoteDomainModel(final List<ModelNodebootOperations) {
        final ModelNode result;
        try {
            // Create the apply-domain-model operation
            final ModelNode operation = .clone();
            operation.get().set(bootOperations);
            // Execute the operation
        } catch (Exception e) {
            return false;
        }
        // If it did not success, don't register it at the DC
        String outcome = result.get().asString();
        boolean success = .equals(outcome);
        if (!success) {
            ModelNode failureDesc = result.hasDefined() ? result.get() : new ModelNode();
            ..failedToApplyDomainConfig(outcomefailureDesc);
        }
        return success;
    }

    
    @Override
    public synchronized void stop(final StopContext context) {
        Thread executorShutdown = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    StreamUtils.safeClose();
                    .shutdownNow();
                } finally {
                    try {
                        .shutdown();
                    } finally {
                        context.complete();
                    }
                }
            }
        }, RemoteDomainConnectionService.class.getSimpleName() + " ExecutorService Shutdown Thread");
        executorShutdown.start();
        context.asynchronous();
    }

    
    @Override
        return this;
    }

    
Analyzes a failure thrown connecting to the master for causes that indicate some problem not likely to be resolved by immediately retrying. If found, throws an exception highlighting the underlying cause. If the cause is not one of the ones understood by this method, the method returns normally.

Throws:
org.jboss.as.domain.controller.SlaveRegistrationException if the remote HC rejected the request
java.lang.IllegalStateException for other failures understood by this method
        Throwable cause = e;
        while ((cause = cause.getCause()) != null) {
            if (cause instanceof SaslException) {
                throw .authenticationFailureUnableToConnect(cause);
            } else if (cause instanceof SSLHandshakeException) {
                throw .sslFailureUnableToConnect(cause);
            } else if (cause instanceof SlaveRegistrationException) {
                throw (SlaveRegistrationExceptioncause;
            }
        }
    }

    
Handles logging tasks related to a failure to connect to a remote HC.

Parameters:
uri the URI at which the connection attempt was made. Can be null indicating a failure to discover the HC
discoveryOption the DiscoveryOption used to determine uri
moreOptions true if there are more untried discovery options
e the exception
    static void logConnectionException(URI uriDiscoveryOption discoveryOptionboolean moreOptionsException e) {
        if (uri == null) {
            ..failedDiscoveringMaster(discoveryOptione);
        } else {
            ..cannotConnect(urie);
        }
        if (!moreOptions) {
            // All discovery options have been exhausted
        }
    }
    private class GetFileRequest extends AbstractManagementRequest<FileVoid> {
        private final byte rootId;
        private final String filePath;
        private final HostFileRepository localFileRepository;
        private GetFileRequest(final byte rootIdfinal String filePathfinal HostFileRepository localFileRepository) {
            this. = rootId;
            this. = filePath;
            this. = localFileRepository;
        }
        @Override
        public byte getOperationType() {
            return .;
        }
        @Override
        protected void sendRequest(ActiveOperation.ResultHandler<FileresultHandlerManagementRequestContext<VoidcontextFlushableDataOutput outputthrows IOException {
            output.write(.);
            output.writeUTF(.getLocalHostName());
        }
        @Override
        public void handleRequest(DataInput inputActiveOperation.ResultHandler<FileresultHandlerManagementRequestContext<Voidcontextthrows IOException {
            final File localPath;
            switch () {
                case .: {
                    localPath = .getFile();
                    break;
                }
                case .: {
                    localPath = .getConfigurationFile();
                    break;
                }
                case .: {
                    byte[] hash = HashUtil.hexStringToByteArray();
                    localPath = .getDeploymentRoot(hash);
                    break;
                }
                default: {
                    localPath = null;
                }
            }
            try {
                ..handleResponse(inputlocalPathresultHandlercontext);
            } catch (CannotCreateLocalDirectoryException e) {
                throw .cannotCreateLocalDirectory(e.getDir());
            } catch (DidNotReadEntireFileException e) {
                throw .didNotReadEntireFile(e.getMissing());
            }
        }
    }
    static class RemoteFileRepository implements HostFileRepository {
        private final HostFileRepository localFileRepository;
        RemoteFileRepository(final HostFileRepository localFileRepository) {
            this. = localFileRepository;
        }
        @Override
        public final File getFile(String relativePath) {
            return getFile(relativePath.);
        }
        @Override
        public final File getConfigurationFile(String relativePath) {
            return getFile(relativePath.);
        }
        @Override
        public final File[] getDeploymentFiles(byte[] deploymentHash) {
            final File root = getDeploymentRoot(deploymentHash);
            return root.listFiles();
        }
        @Override
        public File getDeploymentRoot(byte[] deploymentHash) {
            String hex = deploymentHash == null ? "" : HashUtil.bytesToHexString(deploymentHash);
            final File file = .getDeploymentRoot(deploymentHash);
            if(! file.exists()) {
                return getFile(hex.);
            }
            return file;
        }
        private File getFile(final String relativePathfinal byte repoId) {
            return .getFile(relativePathrepoId);
        }
        void setRemoteFileRepositoryExecutor(RemoteFileRepositoryExecutor remoteFileRepositoryExecutor) {
            this. = remoteFileRepositoryExecutor;
        }
        @Override
        public void deleteDeployment(byte[] deploymentHash) {
            .deleteDeployment(deploymentHash);
        }
    }
    interface RemoteFileRepositoryExecutor {
        File getFile(final String relativePathfinal byte repoIdHostFileRepository localFileRepository);
    }
        public File getFile(final String relativePathfinal byte repoIdHostFileRepository localFileRepository) {
            if(.isConnected()) {
                try {
                    return .executeRequest(new GetFileRequest(repoIdrelativePathlocalFileRepository), null).getResult().get();
                } catch (Exception e) {
                    throw .failedToGetFileFromRemoteRepository(e);
                }
            } else {
                return localFileRepository.getFile(relativePath);
            }
        }
    };
        protected FutureClient() {
            super(null);
        }
        private void setClient(MasterDomainControllerClient client) {
            super.setResult(client);
        }
    }
    private static int getSystemProperty(final String namefinal int defaultValue) {
        final String value = WildFlySecurityManager.getPropertyPrivileged(namenull);
        try {
            return value == null ? defaultValue : Integer.parseInt(value);
        } catch (NumberFormatException ignored) {
            return defaultValue;
        }
    }
    private static class ReadRootResourceHandler implements OperationStepHandler {
        private Resource resource;
            ReadRootResourceHandler handler = new ReadRootResourceHandler();
            executor.execute(new ModelNode(), ...nullhandler);
            return handler.resource;
        }
        @Override
        public void execute(OperationContext contextModelNode operationthrows OperationFailedException {
             = context.readResourceFromRoot(.);
            context.stepCompleted();
        }
    }

    
The tx handling code is copied from ProxyStepHandler
    private static class TransactionalDomainControllerClient {
        private final RemoteProxyController remoteProxy;
             = RemoteProxyController.create(handler..false);
        }
        private ModelNode executeTransactional(OperationContext contextModelNode operation) {
            OperationMessageHandler messageHandler = new DelegatingMessageHandler(context);
            final AtomicReference<ModelNodepreparedResultRef = new AtomicReference<ModelNode>();
            final AtomicReference<ModelNodefinalResultRef = new AtomicReference<ModelNode>();
            final ProxyController.ProxyOperationControl proxyControl = new ProxyController.ProxyOperationControl() {
                @Override
                public void operationPrepared(ModelController.OperationTransaction transactionModelNode result) {
                    txRef.set(transaction);
                    preparedResultRef.set(result);
                }
                @Override
                public void operationFailed(ModelNode response) {
                    finalResultRef.set(response);
                }
                @Override
                public void operationCompleted(ModelNode response) {
                    finalResultRef.set(response);
                }
            };
            .execute(operationmessageHandlerproxyControlnew DelegatingOperationAttachments(context));
            ModelNode finalResult = finalResultRef.get();
            if (finalResult != null) {
                // operation failed before it could commit
                return finalResult;
            }
            context.addStep(new OperationStepHandler() {
                @Override
                public void execute(OperationContext contextModelNode operationthrows OperationFailedException {
                    completeRemoteTransaction(contextoperationtxRefpreparedResultReffinalResultRef);
                }
            }, ..);
            return preparedResultRef.get();
        }
        private void completeRemoteTransaction(OperationContext contextModelNode operation,
                final AtomicReference<ModelController.OperationTransactiontxRef,
                final AtomicReference<ModelNodepreparedResultReffinal AtomicReference<ModelNodefinalResultRef) {
            boolean completeStepCalled = false;
            try {
                context.completeStep(new OperationContext.ResultHandler() {
                    @Override
                    public void handleResult(OperationContext.ResultAction resultActionOperationContext contextModelNode operation) {
                        boolean txCompleted = false;
                        try {
                            ModelController.OperationTransaction tx = txRef.get();
                            try {
                                if (resultAction == ..) {
                                    tx.commit();
                                } else {
                                    tx.rollback();
                                }
                            } finally {
                                txCompleted = true;
                            }
                        } finally {
                            // Ensure the remote side gets a transaction outcome if
                            // we can't commit/rollback above
                            if (!txCompleted && txRef.get() != null) {
                                txRef.get().rollback();
                            }
                        }
                    }
                });
                completeStepCalled = true;
            } finally {
                // Ensure the remote side gets a transaction outcome if we can't
                // call completeStep above
                if (!completeStepCalled && txRef.get() != null) {
                    txRef.get().rollback();
                }
            }
        }
    }
    private static class DelegatingMessageHandler implements OperationMessageHandler {
        private final OperationContext context;
        DelegatingMessageHandler(final OperationContext context) {
            this. = context;
        }
        @Override
        public void handleReport(MessageSeverity severityString message) {
            .report(severitymessage);
        }
    }
    private static class DelegatingOperationAttachments implements OperationAttachments {
        private final OperationContext context;
        private DelegatingOperationAttachments(final OperationContext context) {
            this. = context;
        }
        @Override
        public boolean isAutoCloseStreams() {
            return false;
        }
        @Override
        public List<InputStreamgetInputStreams() {
            int count = .getAttachmentStreamCount();
            List<InputStreamresult = new ArrayList<InputStream>(count);
            for (int i = 0; i < counti++) {
                result.add(.getAttachmentStream(i));
            }
            return result;
        }
        @Override
        public void close() throws IOException {
            //
        }
    }