Search in sources :

Example 1 with CouchDbException

use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.

the class CouchDbPacketSaver method handle.

@Override
public void handle(PacketCollection packetCollection) throws PacketHandleException {
    // Normally we would try and create the database, but that doesn't work with non-admin cookie authenticated users
    String id = packetCollection.getDbId();
    String revision = idMap == null ? null : idMap.get(id);
    final JsonData jsonData;
    try {
        jsonData = new StringJsonData(MAPPER.writeValueAsString(packetCollection));
    } catch (JsonProcessingException e) {
        throw new RuntimeException("Cannot serialize packet collection! This is bad!", e);
    }
    try {
        final DocumentResponse response;
        if (revision == null) {
            response = database.putDocument(id, jsonData);
        } else {
            response = database.updateDocument(id, revision, jsonData);
        }
        LOGGER.debug("Now revision is: " + response.getRev() + ". It was: " + revision);
        if (idMap != null) {
            // Currently, if we have a new document ID, we never, ever, need to worry about using an older document ID, so we can clear the map to avoid keeping unnecessary memory
            idMap.clear();
            idMap.put(id, response.getRev());
        }
    } catch (CouchDbNotFoundException ex) {
        throw new PacketHandleException("Got 'not found'. Does the database exist? Make sure to run the couchdb-setup!", ex);
    } catch (CouchDbUpdateConflictException ex) {
        if (idMap == null) {
            // we are ignoring conflicts
            LOGGER.debug("Got update conflict exception. Ignoring...");
            return;
        }
        try {
            String actualRev = database.getCurrentRevision(id);
            idMap.put(id, actualRev);
            LOGGER.debug("We were able to get the actual Revision ID for id=" + id + " actual rev=" + actualRev);
        } catch (CouchDbException revEx) {
            LOGGER.debug("Unable to get the actual Revision ID for id=" + id, revEx);
        }
        throw new PacketHandleException("Conflict while saving something to couchdb. id=" + id + " rev=" + revision + ". This usually means we put a packet in the database, but we weren't able to cache its rev id.", ex);
    } catch (CouchDbException ex) {
        if (ex.getCause() instanceof IOException) {
            throw new PacketHandleException("We got a DbAccessException probably meaning we couldn't reach the database.", ex);
        } else {
            throw new PacketHandleException("Got a DbAccessException without IOException as a cause. Something must be wrong.", ex);
        }
    }
}
Also used : StringJsonData(me.retrodaredevil.couchdbjava.json.StringJsonData) CouchDbException(me.retrodaredevil.couchdbjava.exception.CouchDbException) DocumentResponse(me.retrodaredevil.couchdbjava.response.DocumentResponse) CouchDbNotFoundException(me.retrodaredevil.couchdbjava.exception.CouchDbNotFoundException) IOException(java.io.IOException) CouchDbUpdateConflictException(me.retrodaredevil.couchdbjava.exception.CouchDbUpdateConflictException) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) JsonData(me.retrodaredevil.couchdbjava.json.JsonData) StringJsonData(me.retrodaredevil.couchdbjava.json.StringJsonData) PacketHandleException(me.retrodaredevil.solarthing.packets.handling.PacketHandleException)

Example 2 with CouchDbException

use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.

the class CacheHandler method queryOrCalculateCaches.

private <T extends CacheDataPacket> List<T> queryOrCalculateCaches(TypeReference<T> typeReference, String cacheName, String sourceId, long startPeriodNumber, long endPeriodNumber) {
    // the document IDs needed to return data
    List<String> documentIds = new ArrayList<>();
    // a map from a document ID to a period number
    Map<String, Long> documentIdPeriodNumberMap = new HashMap<>();
    for (long periodNumber = startPeriodNumber; periodNumber <= endPeriodNumber; periodNumber++) {
        Instant periodStart = getPeriodStartFromNumber(periodNumber);
        String documentId = CacheUtil.getDocumentId(periodStart, duration, sourceId, cacheName);
        documentIds.add(documentId);
        documentIdPeriodNumberMap.put(documentId, periodNumber);
    }
    BulkGetRequest request = BulkGetRequest.from(documentIds);
    final BulkGetResponse response;
    try {
        response = cacheDatabase.getDocumentsBulk(request);
    } catch (CouchDbException e) {
        throw new DatabaseException("CouchDB exception | message: " + e.getMessage(), e);
    }
    // map for documents that need to be updated. The value represents the revision that needs to be used to update it
    Map<String, String> documentIdRevisionMapForUpdate = new HashMap<>();
    // Map for period number -> cached data. This helps us make sure we only return a single piece of data for each period
    Map<Long, T> periodNumberPacketMap = new TreeMap<>();
    // Set for document IDs that we already have and do not need to be updated
    Set<String> doNotUpdateDocumentIdsSet = new HashSet<>();
    Long queryStartPeriodNumber = null;
    Long queryEndPeriodNumber = null;
    for (BulkGetResponse.Result result : response.getResults()) {
        if (result.hasConflicts()) {
            // replication going on with their databases.
            throw new UnexpectedResponseException("cache document with conflict! doc id: " + result.getDocumentId());
        }
        Long periodNumber = documentIdPeriodNumberMap.get(result.getDocumentId());
        if (periodNumber == null) {
            throw new IllegalStateException("Could not get period number for doc id: " + result.getDocumentId() + ". This should never happen.");
        }
        T value = null;
        if (!result.isError()) {
            JsonData jsonData = result.getJsonDataAssertNotConflicted();
            try {
                value = CouchDbJacksonUtil.readValue(mapper, jsonData, typeReference);
                if (value.getSourceId().equals(sourceId) && value.getCacheName().equals(cacheName)) {
                    periodNumberPacketMap.put(periodNumber, value);
                }
                doNotUpdateDocumentIdsSet.add(value.getDbId());
            } catch (JsonProcessingException ex) {
                // If we are in this catch block, one of two things has happened:
                // The JSON is invalid (unlikely), we updated how a given cache is serialized/deserialized, or we're dumb and never tested to see if the deserialization works.
                // If the JSON is actually invalid, getRevisionFromJsonData will throw an exception. Otherwise, we need to calculate the given cache again
                String revision = getRevisionFromJsonData(jsonData);
                documentIdRevisionMapForUpdate.put(result.getDocumentId(), revision);
            }
        }
        if (value == null) {
            if (queryStartPeriodNumber == null) {
                queryStartPeriodNumber = periodNumber;
                queryEndPeriodNumber = periodNumber;
            } else {
                queryStartPeriodNumber = Math.min(queryStartPeriodNumber, periodNumber);
                queryEndPeriodNumber = Math.max(queryEndPeriodNumber, periodNumber);
            }
        }
    }
    if (queryStartPeriodNumber != null) {
        List<CacheDataPacket> calculatedPackets = calculatePeriod(queryStartPeriodNumber, queryEndPeriodNumber);
        List<JsonData> calculatedPacketsJsonDataList = new ArrayList<>();
        int updateAttemptCount = 0;
        for (CacheDataPacket packet : calculatedPackets) {
            if (doNotUpdateDocumentIdsSet.contains(packet.getDbId())) {
                continue;
            }
            if (!sourceId.equals(packet.getSourceId()) || !cacheName.equals(packet.getCacheName())) {
                // This is the same with different cache names, we don't know which ones we need to update and which ones we cannot
                continue;
            }
            JsonData json;
            try {
                String revision = documentIdRevisionMapForUpdate.get(packet.getDbId());
                if (revision == null) {
                    json = new StringJsonData(mapper.writeValueAsString(packet));
                } else {
                    json = new StringJsonData(mapper.writeValueAsString(new DocumentRevisionWrapper(revision, packet)));
                    updateAttemptCount++;
                }
            } catch (JsonProcessingException e) {
                throw new RuntimeException("Should be able to serialize!", e);
            }
            calculatedPacketsJsonDataList.add(json);
        }
        final List<BulkDocumentResponse> postResponse;
        try {
            postResponse = cacheDatabase.postDocumentsBulk(new BulkPostRequest(calculatedPacketsJsonDataList));
        } catch (CouchDbException e) {
            throw new DatabaseException("Could not update cache", e);
        }
        int successCount = 0;
        int failCount = 0;
        for (BulkDocumentResponse documentResponse : postResponse) {
            if (documentResponse.isOk()) {
                successCount++;
            } else {
                failCount++;
                LOGGER.info("Error: " + documentResponse.getError() + " reason: " + documentResponse.getReason() + " on id: " + documentResponse.getId());
            }
        }
        LOGGER.debug("(Cache updating) Success: " + successCount + " fail: " + failCount + ". Tried to update: " + updateAttemptCount);
        int numberOfWantedType = 0;
        for (CacheDataPacket cacheDataPacket : calculatedPackets) {
            if (cacheDataPacket.getSourceId().equals(sourceId) && cacheDataPacket.getCacheName().equals(cacheName)) {
                @SuppressWarnings("unchecked") T packet = (T) cacheDataPacket;
                Long periodNumber = documentIdPeriodNumberMap.get(cacheDataPacket.getDbId());
                if (periodNumber == null) {
                    throw new NullPointerException("No period number for id: " + cacheDataPacket.getDbId());
                }
                periodNumberPacketMap.put(periodNumber, packet);
                numberOfWantedType++;
            }
        }
        LOGGER.debug("Calculated " + calculatedPackets.size() + " and " + numberOfWantedType + " were of type " + cacheName);
    } else {
        LOGGER.trace("Didn't have to get any data");
    }
    return new ArrayList<>(periodNumberPacketMap.values());
}
Also used : JsonData(me.retrodaredevil.couchdbjava.json.JsonData) StringJsonData(me.retrodaredevil.couchdbjava.json.StringJsonData) CacheDataPacket(me.retrodaredevil.solarthing.type.cache.packets.CacheDataPacket) BulkGetResponse(me.retrodaredevil.couchdbjava.response.BulkGetResponse) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) StringJsonData(me.retrodaredevil.couchdbjava.json.StringJsonData) CouchDbException(me.retrodaredevil.couchdbjava.exception.CouchDbException) BulkDocumentResponse(me.retrodaredevil.couchdbjava.response.BulkDocumentResponse) Instant(java.time.Instant) BulkGetRequest(me.retrodaredevil.couchdbjava.request.BulkGetRequest) BulkPostRequest(me.retrodaredevil.couchdbjava.request.BulkPostRequest) UnexpectedResponseException(me.retrodaredevil.solarthing.rest.exceptions.UnexpectedResponseException) DatabaseException(me.retrodaredevil.solarthing.rest.exceptions.DatabaseException) SolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException)

Example 3 with CouchDbException

use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.

the class SolarMain method doMain.

private static int doMain(String[] args) {
    String logMessage = "Beginning main. Jar: " + getJarInfo();
    LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "[LOG] " + logMessage);
    System.out.println("[stdout] " + logMessage);
    System.err.println("[stderr] " + logMessage);
    Cli<CommandOptions> cli = CliFactory.createCli(CommandOptions.class);
    final CommandOptions commandOptions;
    try {
        commandOptions = cli.parseArguments(args);
    } catch (ArgumentValidationException ex) {
        System.out.println(cli.getHelpMessage());
        if (ex instanceof HelpRequestedException) {
            return 0;
        }
        LOGGER.error(SolarThingConstants.SUMMARY_MARKER, ex.getMessage());
        LOGGER.error(SolarThingConstants.SUMMARY_MARKER, "(Fatal)Incorrect args");
        return SolarThingConstants.EXIT_CODE_INVALID_OPTIONS;
    }
    if (commandOptions.getBaseConfigFile() != null) {
        return doMainCommand(commandOptions, commandOptions.getBaseConfigFile());
    }
    if (commandOptions.getCouchDbSetupFile() != null) {
        final DatabaseConfig config;
        try {
            config = ConfigUtil.MAPPER.readValue(commandOptions.getCouchDbSetupFile(), DatabaseConfig.class);
        } catch (IOException e) {
            e.printStackTrace();
            System.err.println("Problem reading CouchDB database settings file.");
            return SolarThingConstants.EXIT_CODE_INVALID_CONFIG;
        }
        DatabaseSettings settings = config.getSettings();
        if (!(settings instanceof CouchDbDatabaseSettings)) {
            System.err.println("Must be CouchDB database settings!");
            return SolarThingConstants.EXIT_CODE_INVALID_CONFIG;
        }
        try {
            return CouchDbSetupMain.createFrom((CouchDbDatabaseSettings) settings).doCouchDbSetupMain();
        } catch (CouchDbException e) {
            if (e instanceof CouchDbCodeException) {
                ErrorResponse error = ((CouchDbCodeException) e).getErrorResponse();
                if (error != null) {
                    System.err.println(error.getError());
                    System.err.println(error.getReason());
                }
            }
            throw new RuntimeException(e);
        }
    }
    List<String> legacyArguments = commandOptions.getLegacyOptionsRaw();
    if (legacyArguments == null || legacyArguments.isEmpty()) {
        System.err.println(cli.getHelpMessage());
        return SolarThingConstants.EXIT_CODE_INVALID_OPTIONS;
    }
    System.err.println("Invalid sub command: " + legacyArguments.get(0));
    return SolarThingConstants.EXIT_CODE_INVALID_OPTIONS;
}
Also used : CouchDbException(me.retrodaredevil.couchdbjava.exception.CouchDbException) ErrorResponse(me.retrodaredevil.couchdbjava.response.ErrorResponse) DatabaseSettings(me.retrodaredevil.solarthing.config.databases.DatabaseSettings) CouchDbDatabaseSettings(me.retrodaredevil.solarthing.config.databases.implementations.CouchDbDatabaseSettings) CouchDbDatabaseSettings(me.retrodaredevil.solarthing.config.databases.implementations.CouchDbDatabaseSettings) HelpRequestedException(com.lexicalscope.jewel.cli.HelpRequestedException) CouchDbCodeException(me.retrodaredevil.couchdbjava.exception.CouchDbCodeException) ArgumentValidationException(com.lexicalscope.jewel.cli.ArgumentValidationException)

Example 4 with CouchDbException

use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.

the class CouchDbMillisDatabase method query.

@Override
public List<StoredPacketGroup> query(MillisQuery query) throws SolarThingDatabaseException {
    final ViewResponse response;
    try {
        response = database.queryView(SolarThingCouchDb.createMillisNullView(CouchDbQueryUtil.createMillisNullParams(query)));
    } catch (CouchDbException e) {
        throw ExceptionUtil.createFromCouchDbException(e);
    }
    List<ViewResponse.DocumentEntry> rows = response.getRows();
    List<StoredPacketGroup> r = new ArrayList<>(rows.size());
    for (ViewResponse.DocumentEntry row : rows) {
        // When using includeDocs=true, we want to use the doc, not its value (which is null with millisNull)
        JsonData jsonData = row.getDoc();
        StoredPacketGroup storedPacketGroup = jsonDataToStoredPacketGroup(jsonData).getPacket();
        r.add(storedPacketGroup);
    }
    return r;
}
Also used : CouchDbException(me.retrodaredevil.couchdbjava.exception.CouchDbException) ViewResponse(me.retrodaredevil.couchdbjava.response.ViewResponse) ArrayList(java.util.ArrayList) StoredPacketGroup(me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup) JsonData(me.retrodaredevil.couchdbjava.json.JsonData) StringJsonData(me.retrodaredevil.couchdbjava.json.StringJsonData)

Example 5 with CouchDbException

use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.

the class CouchDbMillisDatabase method uploadPacketCollection.

@Override
public UpdateToken uploadPacketCollection(PacketCollection packetCollection, UpdateToken updateToken) throws SolarThingDatabaseException {
    final JsonData jsonData;
    try {
        jsonData = new StringJsonData(mapper.writeValueAsString(packetCollection));
    } catch (JsonProcessingException e) {
        throw new RuntimeException("Couldn't serialize the packet collection", e);
    }
    try {
        final DocumentResponse response;
        if (updateToken == null) {
            response = database.putDocument(packetCollection.getDbId(), jsonData);
        } else {
            RevisionUpdateToken revisionUpdateToken = CouchDbSolarThingDatabase.checkUpdateToken(updateToken);
            response = database.updateDocument(packetCollection.getDbId(), revisionUpdateToken.getRevision(), jsonData);
        }
        return new RevisionUpdateToken(response.getRev());
    } catch (CouchDbException e) {
        throw ExceptionUtil.createFromCouchDbException(e);
    }
}
Also used : StringJsonData(me.retrodaredevil.couchdbjava.json.StringJsonData) CouchDbException(me.retrodaredevil.couchdbjava.exception.CouchDbException) DocumentResponse(me.retrodaredevil.couchdbjava.response.DocumentResponse) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) JsonData(me.retrodaredevil.couchdbjava.json.JsonData) StringJsonData(me.retrodaredevil.couchdbjava.json.StringJsonData)

Aggregations

CouchDbException (me.retrodaredevil.couchdbjava.exception.CouchDbException)8 JsonData (me.retrodaredevil.couchdbjava.json.JsonData)6 StringJsonData (me.retrodaredevil.couchdbjava.json.StringJsonData)6 JsonProcessingException (com.fasterxml.jackson.core.JsonProcessingException)4 SolarThingDatabaseException (me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException)3 ArrayList (java.util.ArrayList)2 CouchDbNotFoundException (me.retrodaredevil.couchdbjava.exception.CouchDbNotFoundException)2 CouchDbUpdateConflictException (me.retrodaredevil.couchdbjava.exception.CouchDbUpdateConflictException)2 DocumentResponse (me.retrodaredevil.couchdbjava.response.DocumentResponse)2 ViewResponse (me.retrodaredevil.couchdbjava.response.ViewResponse)2 NotFoundSolarThingDatabaseException (me.retrodaredevil.solarthing.database.exception.NotFoundSolarThingDatabaseException)2 UnauthorizedSolarThingDatabaseException (me.retrodaredevil.solarthing.database.exception.UnauthorizedSolarThingDatabaseException)2 UpdateConflictSolarThingDatabaseException (me.retrodaredevil.solarthing.database.exception.UpdateConflictSolarThingDatabaseException)2 JsonNode (com.fasterxml.jackson.databind.JsonNode)1 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)1 ArgumentValidationException (com.lexicalscope.jewel.cli.ArgumentValidationException)1 HelpRequestedException (com.lexicalscope.jewel.cli.HelpRequestedException)1 IOException (java.io.IOException)1 Instant (java.time.Instant)1 CouchDbCodeException (me.retrodaredevil.couchdbjava.exception.CouchDbCodeException)1