/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed 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. See accompanying
 * LICENSE file.
 */

package com.pivotal.gemfirexd.internal.engine.fabricservice;

import java.sql.SQLException;
import java.util.Properties;
import java.util.Set;

import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.cache.persistence.PersistentMemberID;
import com.pivotal.gemfirexd.FabricServer;
import com.pivotal.gemfirexd.internal.engine.distributed.utils.GemFireXDUtils;

/**
 * Implementation of {@link FabricServer} API. Future product versions may
 * extend this class to alter its behaviour.
 *
 * @author soubhikc
 */
public class FabricServerImpl extends FabricServiceImpl implements FabricServer {

  Object initializationNotification = new Object();
  boolean notified = false;

  @Override
  public boolean isServer() {
    return true;
  }

  /**
   * @see FabricServer#start(Properties)
   */
  @Override
  public void start(Properties bootProperties) throws SQLException {
    start(bootProperties, false);
  }

  /**
   * @see FabricServer#start(Properties, boolean)
   */
  @Override
  public void start(Properties bootProperties,
      boolean ignoreIfStarted) throws SQLException {
    // take locks acquired by IDS.tryReconnect first to avoid deadlock
    // between start and reconnect thread
    synchronized (CacheFactory.class) {
      synchronized (this) {
        try {
          startImpl(bootProperties, ignoreIfStarted, false);
        } catch (Throwable t) {
          Error err;
          if (t instanceof Error && SystemFailure.isJVMFailureError(
              err = (Error)t)) {
            FabricServiceUtils.clearSystemProperties(monitorlite, sysProps);
            SystemFailure.initiateFailure(err);
            // If this ever returns, rethrow the error. We're poisoned
            // now, so don't let this thread continue.
            throw err;
          }
          // Whenever you catch Error or Throwable, you must also
          // check for fatal JVM error (see above).  However, there is
          // _still_ a possibility that you are dealing with a cascading
          // error condition, so you also need to check to see if the JVM
          // is still usable:
          SystemFailure.checkFailure();
          handleThrowable(t);
        }
      }
    }
  }

  /**
   * This method invoked from GemFire to notify waiting for another JVM to
   * initialize for disk GII.
   *
   * NOTE: It is deliberately not synchronized since it can be invoked by a
   * thread other than the booting thread itself which may be stuck waiting for
   * disk region initialization.
   */
  public void notifyWaiting(String regionPath,
      Set<PersistentMemberID> membersToWaitFor, Set<Integer> missingBuckets,
      PersistentMemberID myId, String message) {
    if (GemFireXDUtils.TraceFabricServiceBoot) {
      logger.info("Accepting WAITING notification" +
          (message != null ? ": " + message : ""));
    }
    if (this.serverstatus != State.WAITING) {
      this.previousServerStatus = this.serverstatus;
    }
    this.serverstatus = State.WAITING;
    notifyTableWait();
    notifyWaitingInLauncher(regionPath, membersToWaitFor, missingBuckets, myId,
        message);
  }

  public void notifyTableInitialized() {
    synchronized (initializationNotification) {
      notified = true;
      initializationNotification.notify();
    }
  }

  public void notifyTableWait() {
    synchronized (initializationNotification) {
      notified = true;
      initializationNotification.notify();
    }
  }

  public void waitTableInitialized() throws InterruptedException {
    synchronized (initializationNotification) {
      while (!notified) {
        initializationNotification.wait();
      }
      notified = false;
    }
  }
}

@@ -899,69 +899,8 @@
 ry;%0A
-import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;%0A
 impo
@@ -1329,16 +1329,30 @@
 er %7B%0A%0A  
+private final 
 Object i
@@ -1395,16 +1395,24 @@
 ct();%0A  
+private 
 boolean 
@@ -1419,24 +1419,16 @@
 notified
- = false
 ;%0A%0A  @Ov
@@ -3058,16 +3058,20 @@
 II.%0A   *
+ %3Cp%3E
 %0A   * NO
@@ -4004,32 +4004,35 @@
 ification.notify
+All
 ();%0A    %7D%0A  %7D%0A%0A 
@@ -4025,37 +4025,38 @@
 ;%0A    %7D%0A  %7D%0A%0A  p
-ublic
+rivate
  void notifyTabl
@@ -4175,16 +4175,19 @@
 n.notify
+All
 ();%0A    
@@ -4370,24 +4370,27 @@
 cation.wait(
+500
 );%0A      %7D%0A 

Fix a precheckin hang in FabricServerImpl.waitTableInitialized