/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.machine.server.recipe;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
import com.google.inject.Inject;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.machine.server.spi.RecipeDao;
import org.eclipse.che.commons.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.google.common.base.MoreObjects.firstNonNull;
import static java.util.Collections.emptyList;
/**
* Loads predefined recipes.
*
* <p>It's used for machine template selection during
* creation of workspace or creation any machine in workspace.
*
* @author Anton Korneta
*/
@Singleton
public class RecipeLoader {
private static final Gson GSON = new GsonBuilder().create();
private final Set<String> recipesPaths;
private final RecipeDao recipeDao;
@Inject
@SuppressWarnings("unused")
public RecipeLoader(@Nullable @Named("predefined.recipe.path") Set<String> recipesPaths,
RecipeDao recipeDao) {
this.recipesPaths = firstNonNull(recipesPaths, Collections.<String>emptySet());
this.recipeDao = recipeDao;
}
@PostConstruct
public void start() throws ServerException {
for (String recipesPath : recipesPaths) {
if (recipesPath != null && !recipesPath.isEmpty()) {
for (RecipeImpl recipe : loadRecipes(recipesPath)) {
try {
try {
recipeDao.update(recipe);
} catch (NotFoundException e) {
recipeDao.create(recipe);
}
} catch (ConflictException e) {
throw new ServerException("Failed to store recipe " + recipe, e);
}
}
}
}
}
/**
* Loads recipes by specified path.
*
* @param recipesPath
* path to recipe file
* @return list of predefined recipes
* @throws ServerException
* when problems occurs with getting or parsing recipe file
*/
private List<RecipeImpl> loadRecipes(String recipesPath) throws ServerException {
try (InputStream is = getResource(recipesPath)) {
return firstNonNull(GSON.fromJson(new InputStreamReader(is), new TypeToken<List<RecipeImpl>>() {}.getType()), emptyList());
} catch (IOException | JsonIOException | JsonSyntaxException e) {
throw new ServerException("Failed to get recipes from specified path " + recipesPath, e);
}
}
/**
* Searches for resource by given path.
*
* @param resource
* path to resource
* @return resource InputStream
* @throws IOException
* when problem occurs during resource getting
*/
private InputStream getResource(String resource) throws IOException {
File resourceFile = new File(resource);
if (resourceFile.exists() && !resourceFile.isFile()) {
throw new IOException(String.format("%s is not a file. ", resourceFile.getAbsolutePath()));
}
InputStream is = resourceFile.exists() ? new FileInputStream(resourceFile)
: Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
if (is == null) {
throw new IOException(String.format("Not found resource: %s", resource));
}
return is;
}
}