Java tutorial
// Copyright 2015 The Project Buendia Authors // // 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 distrib- // uted 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 // specific language governing permissions and limitations under the License. package org.projectbuendia.client.diagnostics; import android.app.Application; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import org.apache.http.HttpResponse; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.DefaultHttpClient; import org.projectbuendia.client.model.Concepts; import org.projectbuendia.client.net.OpenMrsConnectionDetails; import org.projectbuendia.client.utils.Logger; import java.io.IOException; import java.net.HttpURLConnection; import java.net.UnknownHostException; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** * A {@link HealthCheck} that checks whether the Buendia API server is up and responding to HTTP * requests at the URL in the "OpenMRS root URL" preference setting. */ public class BuendiaApiHealthCheck extends HealthCheck { private static final Logger LOG = Logger.create(); // Under normal conditions, make requests to the server with this frequency // to check if it's reachable and responding. private static final int CHECK_PERIOD_MS = 20000; // During certain problem conditions, check more often so that when the // problem is resolved, we can hide the snackbar more promptly. private static final int FAST_CHECK_PERIOD_MS = 10000; // These are the issues for which we use the faster checking period. private static final Set<HealthIssue> FAST_CHECK_ISSUES = ImmutableSet.of(HealthIssue.SERVER_HOST_UNREACHABLE, HealthIssue.SERVER_NOT_RESPONDING); // Retrieving a concept should be quick and ensures that the module is both // running and has database access. private static final String HEALTH_CHECK_ENDPOINT = "/concept/" + Concepts.GENERAL_CONDITION_UUID; private final Object mLock = new Object(); private final OpenMrsConnectionDetails mConnectionDetails; private HandlerThread mHandlerThread; private Handler mHandler; private BuendiaModuleHealthCheckRunnable mRunnable; BuendiaApiHealthCheck(Application application, OpenMrsConnectionDetails connectionDetails) { super(application); mConnectionDetails = connectionDetails; } @Override protected void startImpl() { synchronized (mLock) { if (mHandlerThread == null) { mHandlerThread = new HandlerThread("Buendia API Health Check"); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); } if (mRunnable == null) { mRunnable = new BuendiaModuleHealthCheckRunnable(mHandler); } if (!mRunnable.isRunning.getAndSet(true)) { mHandler.post(mRunnable); } } } @Override protected void stopImpl() { synchronized (mLock) { if (mRunnable != null) { mRunnable.isRunning.set(false); mRunnable = null; } if (mHandlerThread != null) { mHandlerThread.quit(); mHandlerThread = null; } mHandler = null; } } protected int getCheckPeriodMillis() { return Sets.intersection(FAST_CHECK_ISSUES, mActiveIssues).isEmpty() ? CHECK_PERIOD_MS : FAST_CHECK_PERIOD_MS; } private class BuendiaModuleHealthCheckRunnable implements Runnable { public final AtomicBoolean isRunning; private final Handler mHandler; public BuendiaModuleHealthCheckRunnable(Handler handler) { isRunning = new AtomicBoolean(false); mHandler = handler; } @Override public void run() { if (!isRunning.get()) { return; } try { String uriString = mConnectionDetails.getBuendiaApiUrl() + HEALTH_CHECK_ENDPOINT; Uri uri = Uri.parse(uriString); if (uri.getHost() == null) { LOG.w("The configured OpenMRS API URL '%1$s' is invalid.", uriString); reportIssue(HealthIssue.SERVER_CONFIGURATION_INVALID); return; } try { HttpClient httpClient = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(uri.toString()); httpGet.addHeader(BasicScheme.authenticate(new UsernamePasswordCredentials( mConnectionDetails.getUser(), mConnectionDetails.getPassword()), "UTF-8", false)); HttpResponse httpResponse = httpClient.execute(httpGet); if (httpResponse.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_OK) { LOG.w("The OpenMRS URL '%1$s' returned unexpected error code: %2$s", uriString, httpResponse.getStatusLine().getStatusCode()); switch (httpResponse.getStatusLine().getStatusCode()) { case HttpURLConnection.HTTP_INTERNAL_ERROR: reportIssue(HealthIssue.SERVER_INTERNAL_ISSUE); break; case HttpURLConnection.HTTP_FORBIDDEN: case HttpURLConnection.HTTP_UNAUTHORIZED: reportIssue(HealthIssue.SERVER_AUTHENTICATION_ISSUE); break; case HttpURLConnection.HTTP_NOT_FOUND: default: reportIssue(HealthIssue.SERVER_NOT_RESPONDING); break; } return; } } catch (UnknownHostException e) { reportIssue(HealthIssue.SERVER_HOST_UNREACHABLE); return; } catch (IOException e) { LOG.w("Could not perform OpenMRS health check using URL '%1$s'.", uriString); return; } resolveAllIssues(); } finally { mHandler.postDelayed(this, getCheckPeriodMillis()); } } } }