/** * User action to import Features from a properties files. * * @param in inpustream from configuration file * @throws IOException Error raised if the configuration cannot be read */ private void opImportFile(FeatureStore store, InputStream in) throws IOException { Map<String, Feature> mapsOfFeat = new XmlParser().parseConfigurationFile(in).getFeatures(); for (Entry<String, Feature> feature : mapsOfFeat.entrySet()) { if (store.exist(feature.getKey())) { store.update(feature.getValue()); } else { store.create(feature.getValue()); } } log.info(mapsOfFeat.size() + " features have been imported."); }
/** * Build Http response when invoking export features. * * @param res http response * @throws IOException error when building response */ private void opExportFile(FeatureStore store, HttpServletResponse res) throws IOException { Map<String, Feature> features = store.readAll(); InputStream in = new XmlParser().exportFeatures(features); ServletOutputStream sos = null; try { sos = res.getOutputStream(); res.setContentType("text/xml"); res.setHeader("Content-Disposition", "attachment; filename=\"ff4j.xml\""); // res.setContentLength() byte[] bbuf = new byte[4096]; int length = 0; while ((in != null) && (length != -1)) { length = in.read(bbuf); sos.write(bbuf, 0, length); } log.info(features.size() + " features have been exported."); } finally { if (in != null) { in.close(); } if (sos != null) { sos.flush(); sos.close(); } } }
/** * User action to update a target feature's description. * * @param req http request containing operation parameters */ @SuppressWarnings("unchecked") private void opUpdateFeatureDescription(FeatureStore store, HttpServletRequest req) { // uid final String featureId = req.getParameter(FEATID); if (featureId != null && !featureId.isEmpty()) { Feature fp = new Feature(featureId, false); // Description final String featureDesc = req.getParameter(DESCRIPTION); if (null != featureDesc && !featureDesc.isEmpty()) { fp.setDescription(featureDesc); } // GroupName final String groupName = req.getParameter(GROUPNAME); if (null != groupName && !groupName.isEmpty()) { fp.setGroup(groupName); } // Strategy final String strategy = req.getParameter(STRATEGY); if (null != strategy && !strategy.isEmpty()) { try { Class<?> strategyClass = Class.forName(strategy); FlippingStrategy fstrategy = (FlippingStrategy) strategyClass.newInstance(); final String strategyParams = req.getParameter(STRATEGY_INIT); if (null != strategyParams && !strategyParams.isEmpty()) { Map<String, String> initParams = new HashMap<String, String>(); String[] params = strategyParams.split(";"); for (String currentP : params) { String[] cur = currentP.split("="); if (cur.length < 2) { throw new IllegalArgumentException( "Invalid Syntax : param1=val1,val2;param2=val3,val4"); } initParams.put(cur[0], cur[1]); } fstrategy.init(featureId, initParams); } fp.setFlippingStrategy(fstrategy); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Cannot find strategy class", e); } catch (InstantiationException e) { throw new IllegalArgumentException("Cannot instanciate strategy", e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Cannot instanciate : no public constructor", e); } } populateFeatureWithPermissions(fp, req); // Creation store.update(fp); log.info(featureId + " has been updated"); } }
/** Display screen */ @RequestMapping(method = RequestMethod.GET) public ModelAndView showPage( HttpServletRequest req, HttpServletResponse res, @RequestParam(value = OPERATION, required = false) String operation, @RequestParam(value = FEATID, required = false) String featureId) throws Exception { // Environment de travail EnvironmenBean envBean = (EnvironmenBean) req.getSession().getAttribute(ATTR_ENVBEAN); if (null == envBean) { return new ModelAndView("redirect:loadConfig.do"); } log.info("Page <FEATURES>, action<GET>, env<" + envBean.getEnvId() + ">"); // Access features through HTTP store (all parsing done) FeatureStore fStore; if ("http".equalsIgnoreCase(envBean.getConnectionMode())) { // Access features through HTTP store (all parsing done) fStore = new FeatureStoreHttp(envBean.getEnvUrl() + "/" + FF4jWebConstants.RESOURCE_FF4J); } else if ("bean".equalsIgnoreCase(envBean.getConnectionMode())) { ClassPathXmlApplicationContext cpax = new ClassPathXmlApplicationContext(envBean.getEnvUrl()); fStore = cpax.getBean(FF4j.class).getFeatureStore(); cpax.close(); } else if ("jmx".equalsIgnoreCase(envBean.getConnectionMode())) { throw new NotImplementedException("JMX Client is not yet implemented"); } else { throw new IllegalArgumentException( "Invalid definition of store within configuration file, avaolable modes are 'http', 'jmx' and 'bean'"); } // Data in the target screen FeaturesBean featBean = new FeaturesBean(); try { // Check parameter to know what to do if (operation != null && !operation.isEmpty()) { log.debug("Performing operation <" + operation + "> on <" + featureId + ">"); if (OP_DISABLE.equalsIgnoreCase(operation)) { opDisableFeature(fStore, featureId); String msg = buildMessage(featureId, "DISABLED"); featBean.setMessage(msg); log.info(msg); } else if (OP_ENABLE.equalsIgnoreCase(operation)) { opEnableFeature(fStore, featureId); featBean.setMessage(buildMessage(featureId, "ENABLED")); } else if (OP_RMV_FEATURE.equalsIgnoreCase(operation)) { opDeleteFeature(fStore, featureId); String msg = buildMessage(featureId, "DELETED"); featBean.setMessage(msg); log.info(msg); } else if (OP_EXPORT.equalsIgnoreCase(operation)) { opExportFile(fStore, res); featBean.setMessage("Feature have been success fully exported"); } } } catch (Exception e) { featBean.setMessageType(MSG_ERROR); featBean.setMessage(e.getMessage()); log.error("Error when retrieving features ", e); } // Updating Bean featBean.setListOfFeatures(new ArrayList<Feature>(fStore.readAll().values())); featBean.setHtmlPermissions(populatePermissionList(envBean)); featBean.setGroupList(fStore.readAllGroups()); // Create view ModelAndView mav = new ModelAndView(VIEW_FEATURES); mav.addObject(ATTR_ENVBEAN, envBean); mav.addObject(ATTR_FEATUREBEAN, featBean); return mav; }
/** * User action to delete a new Feature. * * @param req http request containing operation parameters */ private void opDeleteFeature(FeatureStore store, String id) { if (StringUtils.hasLength(id)) { store.delete(id); log.info(id + " has been deleted"); } }
/** * User action to disable a Feature. * * @param req http request containing operation parameters */ private void opDisableFeature(FeatureStore store, String featureId) { if (featureId != null && !featureId.isEmpty()) { store.disable(featureId); log.info(featureId + " has been disabled"); } }
/** * User action to enable a Feature. * * @param req http request containing operation parameters */ private void opEnableFeature(FeatureStore store, String featureId) { if (featureId != null && !featureId.isEmpty()) { store.enable(featureId); log.info(featureId + " has been successfully enabled"); } }
@RequestMapping(method = RequestMethod.POST) public ModelAndView executeThenShowPage(HttpServletRequest req, HttpServletResponse res) throws Exception { log.info("Page <FEATURES> on action <POST>"); // Environment de travail EnvironmenBean envBean = (EnvironmenBean) req.getSession().getAttribute(ATTR_ENVBEAN); // Access features through HTTP store (all parsing done) FeatureStore storeHTTP = new FeatureStoreHttp(envBean.getEnvUrl() + "/" + FF4jWebConstants.RESOURCE_FF4J); // Data in the target screen FeaturesBean featBean = new FeaturesBean(); try { // Import Features if (ServletFileUpload.isMultipartContent(req)) { List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(req); for (FileItem item : items) { if (item.isFormField()) { if (OPERATION.equalsIgnoreCase(item.getFieldName())) { log.info("Processing action : " + item.getString()); } } else if (FLIPFILE.equalsIgnoreCase(item.getFieldName())) { String filename = FilenameUtils.getName(item.getName()); if (filename.toLowerCase().endsWith("xml")) { opImportFile(storeHTTP, item.getInputStream()); featBean.setMessage( "The file <b>" + filename + "</b> has been successfully imported"); } else { featBean.setMessage("Invalid FILE, must be XML files"); featBean.setMessageType(MSG_ERROR); } } } } else { // Edit Operations String operation = req.getParameter(OPERATION); if (operation != null && !operation.isEmpty()) { if (OP_EDIT_FEATURE.equalsIgnoreCase(operation)) { opUpdateFeatureDescription(storeHTTP, req); featBean.setMessage(buildMessage(req.getParameter(FEATID), "UPDATED")); } else if (OP_CREATE_FEATURE.equalsIgnoreCase(operation)) { opCreateFeature(storeHTTP, req); featBean.setMessage(buildMessage(req.getParameter(FEATID), "ADDED")); } else if (OP_TOGGLE_GROUP.equalsIgnoreCase(operation)) { String groupName = req.getParameter(GROUPNAME); if (groupName != null && !groupName.isEmpty()) { String operationGroup = req.getParameter(SUBOPERATION); if (OP_ENABLE.equalsIgnoreCase(operationGroup)) { storeHTTP.enableGroup(groupName); featBean.setMessage(buildMessageGroup(groupName, "ENABLED")); log.info("Group '" + groupName + "' has been ENABLED."); } else if (OP_DISABLE.equalsIgnoreCase(operationGroup)) { storeHTTP.disableGroup(groupName); featBean.setMessage(buildMessageGroup(groupName, "DISABLED")); log.info("Group '" + groupName + "' has been DISABLED."); } } } else { log.error("Invalid POST OPERATION" + operation); featBean.setMessageType(MSG_ERROR); featBean.setMessage("Invalid REQUEST"); } } } } catch (Exception e) { featBean.setMessageType(MSG_ERROR); featBean.setMessage(e.getMessage()); e.printStackTrace(); } // Updating bean featBean.setListOfFeatures(new ArrayList<Feature>(storeHTTP.readAll().values())); featBean.setHtmlPermissions(populatePermissionList(envBean)); featBean.setGroupList(storeHTTP.readAllGroups()); // Create view ModelAndView mav = new ModelAndView(VIEW_FEATURES); mav.addObject(ATTR_ENVBEAN, envBean); mav.addObject(ATTR_FEATUREBEAN, featBean); return mav; }