com.nimbits.server.io.BlobStoreImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.nimbits.server.io.BlobStoreImpl.java

Source

/*
 * Copyright (c) 2013 Nimbits Inc.
 *
 * 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 expressed or implied.  See the License for the specific language governing permissions and limitations under the License.
 */

package com.nimbits.server.io;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Range;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.nimbits.client.common.Utils;
import com.nimbits.client.constants.Const;
import com.nimbits.client.enums.ServerSetting;
import com.nimbits.client.model.entity.Entity;
import com.nimbits.client.model.point.Point;
import com.nimbits.client.model.value.Value;
import com.nimbits.client.model.value.impl.ValueModel;
import com.nimbits.client.model.valueblobstore.ValueBlobStore;
import com.nimbits.client.model.valueblobstore.ValueBlobStoreFactory;
import com.nimbits.server.defrag.ValueDayHolder;
import com.nimbits.server.gson.deserializer.ValueDeserializer;
import com.nimbits.server.orm.store.ValueBlobStoreEntity;
import com.nimbits.server.transaction.settings.SettingsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;
import javax.jdo.Transaction;
import java.io.*;
import java.lang.reflect.Type;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

@Repository
public class BlobStoreImpl implements BlobStore {
    private final Logger logger = Logger.getLogger(BlobStoreImpl.class.getName());

    private PersistenceManagerFactory persistenceManagerFactory;

    @Autowired
    private SettingsService settingsService;

    private final Gson gson = new GsonBuilder().setDateFormat(Const.GSON_DATE_FORMAT)
            .registerTypeAdapter(Value.class, new ValueDeserializer()).excludeFieldsWithoutExposeAnnotation()
            .create();

    public BlobStoreImpl() {

    }

    public void setPersistenceManagerFactory(PersistenceManagerFactory persistenceManagerFactory) {
        this.persistenceManagerFactory = persistenceManagerFactory;
    }

    private boolean validateOwnership(Entity entity, ValueBlobStore e) {
        return e.getEntityUUID().equals("") || e.getEntityUUID().equals(entity.getUUID());
    }

    @Override
    public List<Value> getTopDataSeries(final Entity entity, final int maxValues, final Date endDate) {
        PersistenceManager pm = persistenceManagerFactory.getPersistenceManager();
        try {

            final List<Value> retObj = new ArrayList<Value>(maxValues);

            final Query q = pm.newQuery(ValueBlobStoreEntity.class);
            q.setFilter("minTimestamp <= t && entity == k");
            q.declareParameters("String k, Long t");
            q.setOrdering("minTimestamp desc");
            q.setRange(0, maxValues);

            final List<ValueBlobStoreEntity> result = (List<ValueBlobStoreEntity>) q.execute(entity.getKey(),
                    endDate.getTime());

            for (final ValueBlobStoreEntity e : result) {
                if (validateOwnership(entity, e)) {
                    List<Value> values = readValuesFromFile(e);
                    logger.info("reading values from blob " + values.size());
                    for (final Value vx : values) {
                        if (vx.getTimestamp().getTime() <= endDate.getTime()) {
                            retObj.add(vx);
                        }

                        if (retObj.size() >= maxValues) {
                            break;
                        }
                    }
                }
            }
            return retObj;
        } finally {
            pm.close();
        }
    }

    @Override
    public List<Value> getTopDataSeries(final Entity entity, final int maxValues) {
        PersistenceManager pm = persistenceManagerFactory.getPersistenceManager();
        try {

            final List<Value> retObj = new ArrayList<Value>(maxValues);

            final Query q = pm.newQuery(ValueBlobStoreEntity.class);
            q.setFilter("entity == k");
            q.declareParameters("String k");
            q.setOrdering("minTimestamp desc");
            q.setRange(0, 1000);

            final List<ValueBlobStoreEntity> result = (List<ValueBlobStoreEntity>) q.execute(entity.getKey());

            for (final ValueBlobStoreEntity e : result) {
                if (validateOwnership(entity, e)) {
                    List<Value> values = readValuesFromFile(e);
                    logger.info("reading values from blob " + values.size());
                    for (final Value vx : values) {
                        retObj.add(vx);

                        if (retObj.size() >= maxValues) {
                            break;
                        }
                    }
                }
            }
            return ImmutableList.copyOf(retObj);
        } finally {
            pm.close();
        }
    }

    @Override
    public List<Value> getDataSegment(final Entity entity, final Range<Date> timespan) {
        PersistenceManager pm = persistenceManagerFactory.getPersistenceManager();
        try {
            final List<Value> retObj = new ArrayList<Value>();
            final Query q = pm.newQuery(ValueBlobStoreEntity.class);
            q.setFilter("entity == k && minTimestamp <= et && maxTimestamp >= st ");
            q.declareParameters("String k, Long et, Long st");
            q.setOrdering("minTimestamp desc");

            final Iterable<ValueBlobStore> result = (Iterable<ValueBlobStore>) q.execute(entity.getKey(),
                    timespan.upperEndpoint().getTime(), timespan.lowerEndpoint().getTime());
            for (final ValueBlobStore e : result) { //todo break out of loop when range is met
                if (validateOwnership(entity, e)) {
                    List<Value> values = readValuesFromFile(e);
                    for (final Value vx : values) {
                        if (timespan.contains(vx.getTimestamp())) {
                            retObj.add(vx);

                        }
                    }
                }
            }
            return retObj;
        } finally {
            pm.close();
        }
    }

    @Override
    public List<ValueBlobStore> getAllStores(final Entity entity) {
        PersistenceManager pm = persistenceManagerFactory.getPersistenceManager();
        try {

            final Query q = pm.newQuery(ValueBlobStoreEntity.class);
            q.setFilter("entity == k");
            q.declareParameters("String k");
            q.setOrdering("timestamp descending");

            final Collection<ValueBlobStore> result = (Collection<ValueBlobStore>) q.execute(entity.getKey());
            List<ValueBlobStore> checked = new ArrayList<>(result.size());
            {
                for (ValueBlobStore e : result) {
                    if (validateOwnership(entity, e)) {
                        checked.add(e);
                    }
                }
            }
            return ValueBlobStoreFactory.createValueBlobStores(checked);
        } finally {
            pm.close();
        }
    }

    @Override
    public void deleteStores(final Entity entity, final Date timestamp) {
        PersistenceManager pm = persistenceManagerFactory.getPersistenceManager();

        final Query q = pm.newQuery(ValueBlobStoreEntity.class);
        q.setFilter("timestamp == t && entity == k");
        q.declareParameters("String k, Long t");

        //  Transaction tx = pm.currentTransaction();
        try {

            //   tx.begin();
            final List<ValueBlobStoreEntity> result = (List<ValueBlobStoreEntity>) q.execute(entity.getKey(),
                    timestamp.getTime());
            pm.deletePersistentAll(result);

            //  tx.commit();

        } catch (Exception ex) {
            ex.printStackTrace();
            //  tx.rollback();

        } finally {
            pm.close();
        }
    }

    @Override
    public List<Value> consolidateDate(final Entity entity, final Date timestamp) {
        PersistenceManager pm = persistenceManagerFactory.getPersistenceManager();

        final Query q = pm.newQuery(ValueBlobStoreEntity.class);
        q.setFilter("timestamp == t && entity == k");
        q.declareParameters("String k, Long t");
        q.setOrdering("timestamp desc");

        try {

            final List<ValueBlobStore> result = (List<ValueBlobStore>) q.execute(entity.getKey(),
                    timestamp.getTime());

            final List<Value> values = new ArrayList<>();
            for (final ValueBlobStore store : result) {
                if (validateOwnership(entity, store)) {
                    values.addAll(readValuesFromFile(store));
                }
            }

            deleteFiles(result);

            return values;
        } catch (Exception ex) {
            return Collections.emptyList(); //TODO if anything goes wrong with this process you'll lose an entire day's worth of data

        } finally {
            pm.close();
        }

    }

    @Override
    public int deleteExpiredData(final Entity entity) {
        PersistenceManager pm = persistenceManagerFactory.getPersistenceManager();

        int exp = ((Point) entity).getExpire();
        int deleted = 0;
        if (exp > 0) {
            Calendar c = Calendar.getInstance();
            c.add(Calendar.DATE, exp * -1);
            try {
                final Query q = pm.newQuery(ValueBlobStoreEntity.class);
                q.setFilter("entity == k && maxTimestamp <= et");
                q.declareParameters("String k, Long et");
                q.setRange(0, 1000);

                final List<ValueBlobStore> result = (List<ValueBlobStore>) q.execute(entity.getKey(),
                        c.getTime().getTime());
                deleted = result.size();

                deleteFiles(result);
                pm.deletePersistentAll(result);

            } finally {
                pm.close();
            }

        }
        return deleted;
    }

    private String readFile(final ValueBlobStore store) throws IOException {
        String path = getPath(store);

        try (BufferedReader br = new BufferedReader(new FileReader(path))) {

            StringBuilder sb = new StringBuilder();
            String line = br.readLine();

            while (line != null) {
                sb.append(line);
                sb.append('\n');
                line = br.readLine();
            }
            return sb.toString();
        }

    }

    private String getFolder() {
        String failover = "/tmp/";
        if (settingsService == null) {
            return failover;
        } else {

            String folder = settingsService.getSetting(ServerSetting.storeDirectory);
            if (folder == null) {
                folder = failover;
            }
            if (!folder.endsWith("/")) {
                folder += "/";
            }
            return folder;
        }
    }

    private List<Value> readValuesFromFile(final ValueBlobStore store) {

        final Type valueListType = new TypeToken<List<ValueModel>>() {
        }.getType();
        List<Value> models;

        try {

            String segment = readFile(store);
            if (!Utils.isEmptyString(segment)) {
                models = gson.fromJson(segment, valueListType);
                if (models != null) {
                    Collections.sort(models);
                } else {
                    models = Collections.emptyList();
                }
            } else {
                models = Collections.emptyList();
            }
            return models;
        } catch (IllegalArgumentException ex) {
            return Collections.emptyList();
        } catch (IOException e) {
            return Collections.emptyList();
        }

    }

    @Override
    public void deleteFiles(List<ValueBlobStore> result) {
        for (ValueBlobStore store : result) {
            String FILENAME = getPath(store);
            File file = new File(FILENAME);
            file.delete();

        }
    }

    private void writeFile(ValueBlobStoreEntity store, String json) {
        FileWriter out;

        try {
            String path = getPath(store);
            File file = new File(path);
            file.getParentFile().mkdirs();
            out = new FileWriter(file);
            out.write(json);
            out.flush();
            out.close();
        } catch (IOException ex) {
            logger.log(Level.SEVERE, "Error writing file", ex);
        }

    }

    private String getPath(ValueBlobStore store) {
        return getFolder() + store.getEntity() + "/" + store.getId();
    }

    @Override
    public List<ValueBlobStore> createBlobStoreEntity(final Entity entity, final ValueDayHolder holder)
            throws IOException {

        logger.info("createBlobStoreEntity");
        PersistenceManager pm = persistenceManagerFactory.getPersistenceManager();

        final String json = gson.toJson(holder.getValues());

        try {
            Range<Date> range = holder.getTimeRange();
            final Date mostRecentTimeForDay = range.upperEndpoint();
            final Date earliestForDay = range.lowerEndpoint();
            final ValueBlobStoreEntity currentStoreEntity = new ValueBlobStoreEntity(entity.getKey(),
                    holder.getStartOfDay(), mostRecentTimeForDay, earliestForDay, BlobStore.storageVersion,
                    entity.getUUID());

            currentStoreEntity.validate();

            pm.makePersistent(currentStoreEntity);
            pm.flush();
            writeFile(currentStoreEntity, json);

            List<ValueBlobStore> result = ValueBlobStoreFactory.createValueBlobStore(currentStoreEntity);

            return ImmutableList.copyOf(result);
        } finally {
            pm.close();
        }

    }

}