コード例 #1
0
 /**
  * Returns a human-readable string representation of the total time
  *
  * @return String total time
  */
 public String getTotalTime() {
   if (recipe != null) {
     return readableTime(recipe.getCookTime() + recipe.getPrepTime());
   } else {
     return "";
   }
 }
コード例 #2
0
 @Test
 public void itAddsNewRecipes() {
   Recipe recipe = new Recipe();
   recipe.setName("Spaghetti");
   recipe.setInstructions("Make it");
   recipeDAO.create(recipe);
   assertEquals(3, recipeDAO.findAll().size());
 }
コード例 #3
0
ファイル: FoodManager.java プロジェクト: DP94/FoodPicker
 public Recipe getRecipeByName(String name) {
   for (Recipe temp : allRecipes) {
     if (temp.getName().equalsIgnoreCase(name)) {
       return temp;
     }
   }
   return null;
 }
コード例 #4
0
 @Test
 public void itUpdatesRecipe() {
   Recipe recipe = recipeDAO.find((long) 1);
   recipe.setName("Lobsters");
   recipeDAO.update(recipe);
   assertEquals(2, recipeDAO.findAll().size());
   assertEquals("Lobsters", recipeDAO.find((long) 1).getName());
 }
コード例 #5
0
  public static Recipe toRecipe(ServerRecipe sr) {
    Recipe ret =
        new Recipe(sr.getAuthor(), sr.getTitle(), sr.getInstructions(), sr.getIngredients());
    for (ServerPhoto sp : sr.photos) {
      ret.addPhoto(ServerPhoto.toPhoto(sp));
    }

    return ret;
  }
コード例 #6
0
 @BeforeClass
 public static void setUpBeforeClass() {
   recipe = new Recipe();
   recipe.setName("storage123456789");
   recipe.setFolder("./src/test/resources/chef/");
   System.out.println("deleting previous instances of the recipe. Errors are expected");
   (new CommandLineInterfaceHelper())
       .runLocalCommand(
           "knife cookbook remove storage123456789 -y -c "
               + Configuration.get("CHEF_CONFIG_FILE"));
 }
コード例 #7
0
 @Override
 public boolean remove(Recipe recipe) {
   if (allRecipes.get(recipe.getIngredients().size()) == null) {
     return false;
   }
   boolean failed = false;
   if (recipe instanceof ShapedRecipe) {
     failed = !removeShaped((ShapedRecipe) recipe);
   } else if (recipe instanceof ShapelessRecipe) {
     failed = !removeShapeless((ShapelessRecipe) recipe);
   }
   failed = !allRecipes.get(recipe.getIngredients().size()).remove(recipe) || failed;
   return !failed;
 }
コード例 #8
0
 /**
  * Returns the total number of images for this recipe
  *
  * @return - the gallery size
  */
 public int getGallerySize() {
   int size = 0;
   if (recipe != null) {
     size = recipe.getImageGallery().size();
   }
   return size;
 }
コード例 #9
0
 /**
  * checks if the user is able to upload
  *
  * @return true if user is authorized false if the user is not
  */
 public boolean shouldRenderUpload() {
   if (recipe != null && ui.isIsUserAuthenticated()) {
     return recipe.getCreator().getUserName().equals(ui.getUser().getUserName());
   } else {
     return false;
   }
 }
コード例 #10
0
 /**
  * Returns a human-readable string representation of the prep time
  *
  * @return String prep time
  */
 public String getReadablePrepTime() {
   if (recipe != null) {
     return readableTime(recipe.getPrepTime());
   } else {
     return "";
   }
 }
コード例 #11
0
 /**
  * Returns true if the user is the creator for this recipe
  *
  * @return boolean
  */
 public boolean isIsCreator() {
   if (ui.isIsUserAuthenticated() && recipe != null) {
     if (recipe.getCreator() == user) return true;
     else return false;
   } else {
     return false;
   }
 }
コード例 #12
0
 public boolean isEditAuthorized() {
   Users user = ui.getUser();
   boolean editAuthorized = false;
   if (user != null && recipe != null) {
     editAuthorized =
         recipe.getCreator().getUserName().equals(user.getUserName()) || ui.isIsAdmin();
   }
   return editAuthorized;
 }
コード例 #13
0
ファイル: Ingredient.java プロジェクト: blomqvie/ruokalista
  /**
   * Saves an ingredient. Before that, it's attached to a recipe.
   *
   * @param recipe
   * @param ingredient
   */
  public static Ingredient saveToRecipe(Long recipe, Ingredient ingredient) {

    Recipe r = Recipe.findById(recipe);
    if (r == null) {
      throw new RuokalistaException("Recipe not found.");
    }

    ingredient.recipe = r;
    save(ingredient);
    return ingredient;
  }
コード例 #14
0
  /** To test equal */
  public void testEquals() {
    /* Fixture */

    /*
     * Recipe book1 = new Recipe( "Title1", "Desc 1","123"); Recipe book1a =
     * new Recipe( "Title1", "Desc 1","123"); Recipe book1m = new Recipe(
     * "Title1a", "Desc 1a","dsdf"); Recipe book2 = new Recipe( "Title2",
     * "Desc 2","sdasd");
     */

    /* Assertions */
    // A book must be equal to itself
    assertTrue(book1.equals(book1));

    // Books with the same isbn are consedered equal, even if their titles
    // and descriptions are different
    // assertTrue(book1.equals(book1m));
    // Books with different isbn are not equal
    assertFalse(book1.getId().equals(book2.getId()));
  }
コード例 #15
0
 @Override
 public boolean register(Recipe recipe) {
   boolean failed = false;
   if (recipe instanceof ShapedRecipe) {
     failed = !registerShaped((ShapedRecipe) recipe);
   } else if (recipe instanceof ShapelessRecipe) {
     failed = !registerShapeless((ShapelessRecipe) recipe);
   } else if (recipe instanceof SmeltedRecipe) {
     failed = !registerSmelted((SmeltedRecipe) recipe);
   } else {
     Spout.log("Unknown recipe type!");
   }
   if (allRecipes.get(recipe.getIngredients().size()) == null) {
     allRecipes.put(
         recipe.getIngredients().size(),
         Collections.newSetFromMap(new ConcurrentHashMap<Recipe, Boolean>()));
   }
   failed = !allRecipes.get(recipe.getIngredients().size()).add(recipe) || failed;
   return !failed;
 }
コード例 #16
0
  /** @brief Method to handle creation of notification */
  private Notification createNotification(Recipe triggered) {
    try {
      // Get shared preferences
      SharedPreferences prefs =
          getApplicationContext().getSharedPreferences("RAOStore", Context.MODE_PRIVATE);
      SharedPreferences.Editor editor = prefs.edit();
      String jsonString = prefs.getString(NOTIFICATION_MAP_NAME, (new JSONObject()).toString());
      JSONObject jsonObject = new JSONObject(jsonString);

      String action = triggered.getDoList().get(0);
      Log.i(TAG, "Found matching recipe. Performing action: " + action);

      // Create null notification
      Notification not = null;
      System.out.println("Action is : " + action);
      // Check what this action was
      if (action.equals(Constants.DROP_PIN)) {
        // If drop pin, get location and create notification
        Log.e(TAG, "Creating notification");
        Location notifLoc = getLocation();

        not = new Notification(triggered.getName(), action, notifLoc);
      } else if (action.equals("Silence Phone")) {
        AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        audio.setRingerMode(0);

        not = new Notification(triggered.getName(), action);
      }

      if (not != null) {
        // Add notification to shared preferences
        jsonObject.put(not.getName(), not.toString());
        editor.putString(NOTIFICATION_MAP_NAME, jsonObject.toString());
        editor.commit();
      }
      return not;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }
コード例 #17
0
 @Transactional
 public void PrepareDish(Dish dish, Employee employee, OrderNum orderNum, Date date)
     throws EmptyRecipeException, NotEnoughStockException {
   List<Ingredient> missingIngredients = stockDao.getIngredientsMissingOnStock(dish);
   if (missingIngredients.size() == 0) {
     List<Recipe> recipeList = recipeDao.getAllByDish(dish);
     for (Recipe r : recipeList) {
       Ingredient ingredient = r.getIngredient();
       Stock stock = stockDao.getStockByName(r.getIngredient().getIngredientName());
       Double qty = stock.getQty() - r.getQty();
       if (qty > 0) {
         stock.setQty(qty);
         stockDao.add(stock);
       } else throw new NotEnoughStockException("Not enough ingredient on stock", stock);
     }
     PreparedDish preparedDish = new PreparedDish();
     preparedDish.setDish(dish);
     preparedDish.setEmployee(employee);
     preparedDish.setOrder(orderNum);
     preparedDish.setPrepareDate(date);
     add(preparedDish);
   } else throw new NotEnoughStockException("Not enough ingredient on stock", null);
 }
コード例 #18
0
ファイル: JSONUtil.java プロジェクト: hornet2319/Task
  public List<Recipe> getSearchList(int page) {
    List<Recipe> list = new ArrayList<>();
    Recipe recipe;
    URL url = null;
    try {
      url = new URL(builder.getSearchURL(page, ingredients, sort));
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
    String recipeJsonData = getRecipeJsonData(url);

    // These are the names of the JSON objects that need to be extracted.
    final String OWM_LIST = "recipes";
    final String OWM_PUBLISHER = "publisher";
    final String OWM_TITLE = "title";
    final String OWM_SOURCE_URL = "source_url";
    final String OWM_RECIPE_ID = "recipe_id";
    final String OWM_IMAGE_URL = "image_url";
    final String OWM_SOCIAL_RANK = "social_rank";
    final String OWM_PUBLISHER_URL = "publisher_url";

    JSONObject jsonObject = null;

    try {
      jsonObject = new JSONObject(recipeJsonData);

      JSONArray recipesArray = jsonObject.getJSONArray(OWM_LIST);

      for (int i = 0; i < recipesArray.length(); i++) {
        recipe = new Recipe();

        JSONObject recipeObj = (JSONObject) recipesArray.get(i);
        recipe.setPublisher(recipeObj.getString(OWM_PUBLISHER));
        recipe.setTitle(recipeObj.getString(OWM_TITLE));
        recipe.setSource_url(recipeObj.getString(OWM_SOURCE_URL));
        recipe.setRecipe_id(recipeObj.getString(OWM_RECIPE_ID));
        recipe.setImage_url(recipeObj.getString(OWM_IMAGE_URL));
        recipe.setSocial_rank(recipeObj.getString(OWM_SOCIAL_RANK));
        recipe.setPublisher_url(recipeObj.getString(OWM_PUBLISHER_URL));
        list.add(recipe);
      }
    } catch (JSONException e) {
      e.printStackTrace();
    }
    return list;
  }
コード例 #19
0
 /**
  * returns true if it has been reviewed and false if it has not been reviewed by a professional;
  */
 public boolean isHasAlreadyReviewed() {
   boolean result = false;
   if (ui.isIsUserAuthenticated() && professionalStatus.isIsProfessional()) {
     Users user = ui.getUser();
     if (recipe != null) {
       for (Review rev : recipe.getReviews()) {
         if (rev.getReviewer().getUserName().equals(user.getUserName())) {
           result = true;
           break;
         }
       } // end for
     }
   } // end value != null
   return result;
 }
コード例 #20
0
  /** This method is called AFTER the bean is constructed */
  @PostConstruct
  private void init() {
    if (!FacesContext.getCurrentInstance().isPostback()) {
      // TODO: view counter ++
    }
    // Get the recipe
    String value = qm.get("recipe");
    if (value != null) {
      recipe = recipesEJB.findRecipe(Integer.parseInt(value));
    }

    // init some fields
    tags = new DefaultTagCloudModel();
    newComment = new Comment();
    newRating = new RecipeRating();
    tags = new DefaultTagCloudModel();

    if (recipe != null) {
      this.commentModel = new LazyCommentDataModel(recipe, recipesEJB);
      this.totalRatings = ratingEJB.countTotalRatings(recipe);
      Users user = ui.getUser();
      getNutritionixIngredientInfo(recipe);
      recipesEJB.incrementViews(recipe);

      // Get the recipe's tags
      ArrayList<Tag> tagList = new ArrayList<Tag>(recipe.getTags());
      if (!tagList.isEmpty()) {
        ListIterator i = tagList.listIterator();
        while (i.hasNext()) {
          Tag t = (Tag) i.next();
          String url = "search.xhtml?searchArg=" + t.getTagName();
          this.tags.addTag(new DefaultTagCloudItem(t.getTagName(), url, tagEJB.getWeight(t)));
        }
      } else {
        this.tags.addTag(new DefaultTagCloudItem("#tagMe", 1));
      }

      // Get related recipes
      relatedRecipes = search.getSearchRecipes(recipe);

    } // end if recipe is null
    else {
      this.tags.addTag(new DefaultTagCloudItem("#tagMe", 1));
    }
    if (ui.isIsUserAuthenticated()) {
      user = ui.getUser();
    }
  }
コード例 #21
0
ファイル: JSONUtil.java プロジェクト: hornet2319/Task
  public Recipe getRecipe(String rId) {
    Recipe recipe;
    String recipeJsonData;
    URL url = null;
    try {
      url = new URL(builder.getGET_URL(rId));
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
    recipeJsonData = getRecipeJsonData(url);
    final String OWM_LIST = "recipe";
    final String OWM_PUBLISHER = "publisher";
    final String OWM_TITLE = "title";
    final String OWM_SOURCE_URL = "source_url";
    final String OWM_RECIPE_ID = "recipe_id";
    final String OWM_IMAGE_URL = "image_url";
    final String OWM_SOCIAL_RANK = "social_rank";
    final String OWM_PUBLISHER_URL = "publisher_url";
    final String OWM_INGREDIENTS = "ingredients";

    JSONObject jsonObject = null;
    recipe = new Recipe();
    try {
      jsonObject = new JSONObject(recipeJsonData);
      JSONObject recipeObj = (JSONObject) jsonObject.getJSONObject(OWM_LIST);

      recipe.setPublisher(recipeObj.getString(OWM_PUBLISHER));
      recipe.setTitle(recipeObj.getString(OWM_TITLE));
      recipe.setSource_url(recipeObj.getString(OWM_SOURCE_URL));
      recipe.setRecipe_id(recipeObj.getString(OWM_RECIPE_ID));
      recipe.setImage_url(recipeObj.getString(OWM_IMAGE_URL));
      recipe.setSocial_rank(recipeObj.getString(OWM_SOCIAL_RANK));
      recipe.setPublisher_url(recipeObj.getString(OWM_PUBLISHER_URL));
      recipe.setIngredients(recipeObj.getString(OWM_INGREDIENTS));

    } catch (JSONException e) {
      e.printStackTrace();
    }
    return recipe;
  }
コード例 #22
0
 /**
  * Creates a comment and redirects back to the recipe page
  *
  * @return the string navigation outcome
  */
 public String doCreateComment() {
   Users commenter = ui.getUser();
   try {
     this.newComment.setRecipe(this.recipe);
     this.newComment.setCommenter(commenter);
     this.newComment.setDateCommented(new Date().getTime());
     List<Comment> c = recipe.getComments();
     c.add(newComment);
     this.recipe.setComments(c);
     recipesEJB.editRecipe(recipe);
   } catch (javax.ejb.EJBAccessException ejbae) {
     FacesContext.getCurrentInstance()
         .addMessage(null, new FacesMessage("Only registered users can post comments."));
   }
   return "/recipe.xhtml?recipe=" + qm.get("recipe");
 }
コード例 #23
0
 @Before
 public void setUp() {
   Recipe recipe_one = new Recipe();
   Recipe recipe_two = new Recipe();
   recipe_one.setId((long) 1);
   recipe_one.setName("Shrimps");
   recipe_one.setInstructions("Instructions");
   recipe_two.setId((long) 2);
   recipe_two.setName("Salad");
   recipe_two.setInstructions("Instructions");
   SessionFactory factory = new Configuration().configure().buildSessionFactory();
   Session session = factory.openSession();
   Transaction transaction = session.beginTransaction();
   session.save(recipe_one);
   session.save(recipe_two);
   transaction.commit();
   session.close();
 }
コード例 #24
0
  public ServerRecipe(Recipe recipe) {
    this.author = recipe.getAuthor();
    this.title = recipe.getTitle();
    this.instructions = recipe.getInstructions();
    this.ingredients = recipe.getIngredients();
    this.uri = recipe.getUri();

    ArrayList<Photo> photos = recipe.getPhotos();
    this.photos = new ArrayList<ServerPhoto>();
    ServerPhoto temp;
    for (Photo p : photos) {
      temp = new ServerPhoto(p);
      this.photos.add(temp);
    }
  }
コード例 #25
0
ファイル: FoodManager.java プロジェクト: DP94/FoodPicker
 public void printFromDatabase(String name) {
   Recipe recipe = connection.getRecipeByName(name);
   System.out.println(recipe.toString());
 }
コード例 #26
0
 public static boolean testMultiplyAllAmounts(
     Recipe initial, double multiplier, Recipe comparison) {
   Recipe result = initial.multiplyAllAmounts(multiplier);
   return result.equals(comparison);
 }
コード例 #27
0
 // Test Cases for the Recipe Class
 public static boolean testFindIngredient(Ingredient ingredient, Recipe recipe) {
   Ingredient ingredientFound = recipe.findIngredient(ingredient.getItem());
   return ingredientFound.equals(ingredient);
 }
コード例 #28
0
  /**
   * @param homeUrl url or canonical path to the cookbook
   * @param local true if it is a canonical path (to a cloned cookbook) and not a URL.
   * @throws CookbookUrlException
   * @throws MetadataParseException
   * @throws se.kth.karamel.common.exception.ValidationException
   */
  public KaramelizedCookbook(String homeUrl, boolean local)
      throws CookbookUrlException, MetadataParseException, ValidationException {
    if (local) {
      Settings.USE_CLONED_REPO_FILES = true;
    }
    CookbookUrls.Builder builder = new CookbookUrls.Builder();
    this.urls = builder.url(homeUrl).build();
    try {
      List<String> defaultsLines = IoUtils.readLines(urls.attrFile);
      this.defaultRb = new DefaultRb(defaultsLines);
      String metadataContent = IoUtils.readContent(urls.metadataFile);
      this.metadataRb = MetadataParser.parse(metadataContent);
      this.metadataRb.normalizeRecipeNames();
      this.metadataRb.setDefaults(defaultRb);
      String karamelFileContent = IoUtils.readContent(urls.karamelFile);
      this.karamelFile = new KaramelFile(karamelFileContent);
      List<String> berksfileLines = IoUtils.readLines(urls.berksFile);
      this.berksFile = new Berksfile(berksfileLines);
    } catch (IOException e) {
      Settings.USE_CLONED_REPO_FILES = false;
      throw new CookbookUrlException("", e);
    }

    List<Recipe> recipes = this.metadataRb.getRecipes();
    for (Recipe r : recipes) {
      String name = r.getName();
      if (name == null || name.isEmpty()) {
        throw new MetadataParseException("Invalid recipe name in metadata.rb");
      }
      String[] recipeData = r.getName().split(Settings.COOKBOOK_DELIMITER);
      // assume recipe name is 'default'
      String experimentFilename = "default.rb";
      if (recipeData.length > 1) {
        experimentFilename = recipeData[1] + ".rb";
      }
      String description = r.getDescription();
      String searchStr = "configFile=";
      int confPos = description.indexOf(searchStr);
      String configFileName = "";
      String configFileContents = "";
      String experimentContent;
      if (confPos != -1 && confPos < description.length() + searchStr.length()) {
        String desc = description.substring(confPos + searchStr.length());
        int pos = desc.indexOf(";");
        if (pos != -1) {
          configFileName = desc.substring(0, pos);
          int pathPos = configFileName.lastIndexOf("/");
          if (pathPos != -1) {
            configFileName = configFileName.substring(pathPos + 1);
          }
        }
      }
      if (!configFileName.isEmpty()) {
        String configFileUrl =
            urls.cookbookRawUrl
                + File.separator
                + "templates"
                + File.separator
                + "defaults"
                + File.separator
                + configFileName
                + ".erb";
        try {
          configFileContents = IoUtils.readContent(configFileUrl);
        } catch (IOException ex) {
          logger.info("Not found in this cookbook: " + urls.recipesHome + experimentFilename, ex);
        }
      }

      ExperimentRecipe er = null;
      try {
        // Only parse experiment recipes here, parse the install.rb recipe later.
        if (experimentFilename.compareTo(Settings.INSTALL_RECIPE + ".rb") != 0) {
          experimentContent = IoUtils.readContent(urls.recipesHome + experimentFilename);
          er =
              ExperimentRecipeParser.parse(
                  r.getName(), experimentContent, configFileName, configFileContents);
        }
      } catch (IOException ex) {
        logger.debug(
            "This cookbook does not have a karamelized experiment: "
                + urls.recipesHome
                + experimentFilename
                + " - "
                + ex.getMessage());
      } catch (RecipeParseException ex) {
        logger.warn(
            "The recipe is not in a karamelized format: "
                + urls.recipesHome
                + experimentFilename
                + " - "
                + ex.getMessage());
      }

      if (er != null) {
        experimentRecipes.add(er);
      }
    }

    try {
      String installContent = IoUtils.readContent(urls.recipesHome + "install.rb");
      this.installRecipe = InstallRecipeParser.parse(installContent);
    } catch (IOException ex) {
      throw new CookbookUrlException(
          "Could not find the file 'recipes/install.rb'. Does the file exist? Is the Internet working?");
    } catch (RecipeParseException ex) {
      logger.warn(
          "Install recipe not in a format that can be used by Karamel Experiments: "
              + urls.recipesHome
              + "install.rb"
              + " - "
              + ex.getMessage());

    } finally {
      Settings.USE_CLONED_REPO_FILES = false;
    }
  }
コード例 #29
0
ファイル: RecipeModule.java プロジェクト: praveensastry/rakam
  @Override
  protected void setup(Binder binder) {
    RecipeConfig recipes = buildConfigObject(RecipeConfig.class);

    Multibinder<HttpService> httpServices = Multibinder.newSetBinder(binder, HttpService.class);
    httpServices.addBinding().to(RecipeHttpService.class).in(Scopes.SINGLETON);

    if (recipes.getRecipes() == null) {
      return;
    }

    boolean set_default = false;
    for (String recipeConfig : recipes.getRecipes()) {
      URI recipeUri;
      try {
        recipeUri = new URI(recipeConfig);
      } catch (URISyntaxException e) {
        throw Throwables.propagate(
            new InvalidConfigurationException("The value of 'recipe' config must be an URI."));
      }

      String path = "/" + recipeUri.getHost() + recipeUri.getPath();
      InputStream stream;
      switch (recipeUri.getScheme()) {
        case "file":
          try {
            stream = new FileInputStream(path);
          } catch (FileNotFoundException e) {
            throw Throwables.propagate(e);
          }
          break;
        case "resources":
          stream = getClass().getResourceAsStream(path);
          if (stream == null) {
            throw new IllegalArgumentException("Recipe file couldn't found: " + recipeUri);
          }
          break;
        case "http":
        case "https":
          try {
            stream = recipeUri.toURL().openStream();
          } catch (IOException e) {
            binder.addError("The value of 'recipe' property '%s' is not an URL");
            return;
          }
          break;
        default:
          binder.addError(
              "The scheme of 'recipe' %s is not valid", recipeConfig, recipeUri.getScheme());
          return;
      }

      ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
      mapper.registerModule(
          new SimpleModule() {
            @Override
            public void setupModule(SetupContext context) {
              context.insertAnnotationIntrospector(new SwaggerAnnotationIntrospector_());
            }
          });
      Recipe recipe;
      try {
        recipe = mapper.readValue(stream, Recipe.class);
      } catch (IOException e) {
        binder.addError("'recipes' file %s couldn't parsed: %s", recipeConfig, e.getMessage());
        return;
      }

      switch (recipe.getStrategy()) {
        case DEFAULT:
          if (set_default) {
            binder.addError("Only one recipe can use DEFAULT strategy.");
            return;
          }
          binder.bind(Recipe.class).toInstance(recipe);
          binder.bind(RecipeLoader.class).asEagerSingleton();
          binder.bind(RecipeHandler.class).in(Scopes.SINGLETON);
          set_default = true;
          break;
        case SPECIFIC:
          Multibinder<InjectionHook> hooks = Multibinder.newSetBinder(binder, InjectionHook.class);
          hooks.addBinding().toInstance(new RecipeLoaderSingle(recipe));
          break;
        default:
          throw new IllegalStateException();
      }
    }
  }
コード例 #30
0
ファイル: RecipeModule.java プロジェクト: praveensastry/rakam
 @Override
 public void call() {
   metastore.createProject(recipe.getProject());
 }