Using the same for-each loop inside 2 different method, is there any way to reduce code duplication here?
1st code
for (AjaxControlBean controlBean : requestData.getControls()) {
if (StringUtils.isAnyBlank(controlBean.getId(), controlBean.getName()) || "repeat".equalsIgnoreCase(controlBean.getType()))
{
continue;
}
FormInstanceControl control = formInstance.getControl(controlBean.getId());
if (control == null) {
control = new FormInstanceControl();
control.setFormInstance(formInstance);
control.setControlId(controlBean.getId());
formInstance.putControl(control);
}
if (controlBean.getValues() != null) {
if (control.getData() != null)
control.getData().clear();
else
control.setData(new ArrayList<FormInstanceData>());
for (String value : controlBean.getValues()) {
FormInstanceData data = new FormInstanceData();
data.setControl(control);
data.setType(FormInstanceData.TYPE_TEXT);
data.setText(value);
control.getData().add(data);
}
}
}
2nd code
for (AjaxControlBean controlBean : requestData.getControls()) {
if (StringUtils.isAnyBlank(controlBean.getId(), controlBean.getName()) || "repeat".equalsIgnoreCase(controlBean.getType())) {
continue;
}
FormInstanceControl control = formInstance.getControl(controlBean.getId());
if (control == null) {
control = new FormInstanceControl();
control.setFormInstance(formInstance);
control.setControlId(controlBean.getId());
formInstance.putControl(control);
}
if (controlBean.getValues() != null) {
if (control.getData() != null) {
control.getData().clear();
}
else
{
control.setData(new ArrayList<FormInstanceData>());
}
int i = 0;
for (String value : controlBean.getValues()) {
FormInstanceData data = new FormInstanceData();
data.setControl(control);
data.setType(FormInstanceData.TYPE_TEXT);
data.setText(value);
data.setIdx(i++);
control.getData().add(data);
}
}
}
the only difference it has is the data.setIdx(i++); Please let me know if there is anything i can do to reduce number of lines
You could factor out a method that takes a FormInstanceControl and a AjaxControlBean as arguments. Then you've got all you need:
private void addBeanData( FormInstanceControl control, AjaxControlBean controlBean) {
int i = 0;
for (String value : controlBean.getValues()) {
FormInstanceData data = new FormInstanceData();
data.setControl(control);
data.setType(FormInstanceData.TYPE_TEXT);
data.setText(value);
data.setIdx(i++);
control.getData().add(data);
}
}
This assumes, the first snippet doesn't break if the Idx is set, even if it's not done there in the original code.
Usage: Where before you had the for-loops, you just do addBeanData( control, controlBean );
Related
Suppose I have the following run() method:
public void run()
{
String responseLine = "";
responseCount = 0;
try
{
while ((responseLine = is.readLine()) != null)
{
if(responseLine!=null && !responseLine.equals(null) && responseLine!="null" && !responseLine.equals("null") && !responseLine.contains("null"))
{
System.out.println(responseLine);
responseCount = responseCount + 1;
}
else if(responseLine.contains("null") || responseLine.equals("null") || responseLine==null || responseLine.equals(null) || responseLine.isEmpty() == true)
{
}
}
closed = true;
}
catch (IOException e)
{
}
}
Notice: the line that says while((responseLine = is.readLine())!=null) is stopped when control D on mac (or control Z on windows) is pressed (null is entered from standard input).
Goal: What changes can I make to the code that will instead say while((responseLine = is.readLine())!=ControlC))?
OR
Let's assume the user presses control D which makes responseLine null, what changes could I make to the code inside the while loop to call control C in the console using java code?
Full code:
https://www.dropbox.com/s/r5buwert7ibybof/JavaChatProgram.zip?dl=0
I have the below if statements check which looks not correct to me as they are multiple if's check please advise how can i reduce them as since looking technically also multiple if checks is been done
String incomingProduct = brokerInvoice.getProduct();
if (incomingProduct!= null && incomingProduct.equalsIgnoreCase("CD") ) {
brokerInvoice.setSourceSystem((String)configuration.getConfiguration().get("CD"));
}
if (incomingProduct!= null && incomingProduct.equalsIgnoreCase("COMMODITY") ) {
brokerInvoice.setSourceSystem((String)configuration.getConfiguration().get("CQD"));
}
if (incomingProduct!= null && incomingProduct.equalsIgnoreCase("DITY") ) {
brokerInvoice.setSourceSystem((String)configuration.getConfiguration().get("DITY"));
}
if (incomingProduct!= null && incomingProduct.equalsIgnoreCase("ITY") ) {
brokerInvoice.setSourceSystem((String)configuration.getConfiguration().get("ITY"));
}
if (incomingProduct!= null && incomingProduct.equalsIgnoreCase("CO") ) {
brokerInvoice.setSourceSystem((String)configuration.getConfiguration().get("CO"));
}
if (incomingProduct!= null && incomingProduct.equalsIgnoreCase(MODITY") ) {
brokerInvoice.setSourceSystem((String)configuration.getConfiguration().get("MODITY"));
}
Folks please advise if I can use map data structure here
String[] products = new String[6]
products[0] = "CD";
products[1] = "COMMODITY";
products[2]= "DITY";
products[3] = "IT";
products[4] = "CO";
products[5] = "MODITY";
for(int i = 0; i < products.length; i++){
if (incomingProduct!= null && incomingProduct.equalsIgnoreCase(products[i]) ) {
brokerInvoice.setSourceSystem((String)configuration.getConfiguration().get(products[i]));
}
}
This should work and be more readable
Optimal variant:
if (incomingProduct!= null) {
switch(incomingProduct.toLowerCase()){
case "cd": doSomethingWithProduct(incomingProduct.toUpperCase());
break;
case "commodity": doSomethingWithProduct(incomingProduct.toUpperCase());
break;
}
}
doSomethingWithProduct(String name){
brokerInvoice.setSourceSystem((String)configuration.getConfiguration().get(name));
}
Supposing you can avoid checking that the incomingProduct is in {"CD", "CO", "COMMODITY", "DITY", "ITY", "MODITY"} you should simply write:
String incomingProduct = brokerInvoice.getProduct();
if (incomingProduct != null) {
brokerInvoice.setSourceSystem((String) configuration.getConfiguration().get(incomingProduct));
}
Otherwise you may go with doge's answer.
Assuming the "COMMODITY" -> "CQD" case is deliberate:
private static final TreeMap<String, String> MAPPINGS = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
static {
MAPPINGS.put("CD", "CD");
MAPPINGS.put("COMMODITY", "CQD");
MAPPINGS.put("DITY", "DITY");
MAPPINGS.put("ITY", "ITY");
MAPPINGS.put("CO", "CO");
MAPPINGS.put("MODITY", "MODITY");
}
void doThings() {
String incomingProduct = brokerInvoice.getProduct();
if (incomingProduct != null) {
String configKey = MAPPINGS.get(incomingProduct);
if (configKey != null) {
brokerInvoice.setSourceSystem((String) configuration.getConfiguration().get(configKey));
}
}
}
I have a scenario where I need to fetch 500 from web service api and display the final output values as comma separated values like id,name,owner,account,path,ccvalues. To achieve this I am writing a method where Iam getting all this information and setting to one java object. Fields are below. Finally i created one list which holds this Video objects. videos.add(video)
String identifier;
String name;
String ownerName;
String accountName;
String mediaPath;
List<KalturaLanguage> ccList;
Now how to display my output from videos list object. Please help me resolving this.
code is:
for (String mediaId : mediaList) {
if (mediaId != null) {
String mediaFullPath = getMediaPath(mediaId);
entryInfo = getMedia(mediaId);
metadataList = getMetadata(mediaId);
ccs = getClosedCaptions(mediaId);
if (entryInfo != null) {
video = new Video();
System.out.println("entryInfo.id"
+ entryInfo.id);
System.out.println("entryInfo.name"
+ entryInfo.name);
System.out.println("mediaFullPath"
+ mediaFullPath);
video.setIdentifier(entryInfo.id);
video.setName(entryInfo.name);
video.setMediaPath(mediaFullPath);
}
if (metadataList != null
&& metadataList.totalCount != 0) {
List<KalturaMetadata> metadataObjs = metadataList.objects;
if (metadataObjs != null
&& metadataObjs.size() > 0) {
for (int i = 0; i < metadataObjs.size(); i++) {
KalturaMetadata metadata = metadataObjs
.get(i);
if (metadata != null) {
if (metadata.xml != null) {
metadataValues = parseXml(metadata.xml);
if (metadataValues.size() != 0) {
ibmAccountList = metadataValues
.get(0);
for (String account : ibmAccountList) {
System.out
.println("IBM Account Name ------->"
+ account);
video.setAccountName(account);
}
ownerList = metadataValues
.get(1);
for (String owner : ownerList) {
System.out
.println("Account Owner Name ------->"
+ owner);
video.setOwnerName(owner);
}
}
}
}
}
}
}
}
if (ccs.size() != 0) {
for (Map.Entry<String, List<KalturaCaptionAsset>> entry : ccs
.entrySet()) {
String key = entry.getKey();
List<KalturaCaptionAsset> values = entry
.getValue();
// System.out.println("Key = " + key);
for (KalturaCaptionAsset asset : values) {
System.out.println(" CC value : "
+ asset.language);
ccList.add(asset.language);
video.setCcList(ccList);
videos.add(video);
}
}
}
}
You are going in a wrong direction. Just implement your toString method inside Video class.
When you iterate over list and print video object it calls toString method inside the video class.
While providing implementation in video class, generate a String in required format.
My project need to parse two type of text data into database.
one format is like this:
<lineNumber>19</lineNumber>
<begin>
2013-08-15,2013-08-15,pek001,123456,08654071,CANX,,,,,,011
<end>
one is like that
<lineNumber>27</lineNumber>
<begin>
2012-11-02,08683683,pek001,00001234,vvip,1
<end>
the difference of the two text is between the begin and end tag.
so our parsing code come out:
first one is:
inputStreamReader = new InputStreamReader(new FileInputStream(FileOne),"gbk"); --different place
br=new BufferedReader(inputStreamReader);
lineNumber = 0;
boolean isDataContent = false;
while (br.ready()) {
String line = br.readLine();
if(line == null){
continue;
}
if(line.contains("<lineNumber>"))
{
try {
lineNumber = Integer.parseInt(StringTools.getDigitalInString(line));
} catch (NumberFormatException e) {
log.error("there is no lineNumber。");
}
continue;
}
if(line.trim().equals("<begin>"))
{
isDataContent = true;
continue;
}
if(line.trim().equals("<end>"))
{
break;
}
if(isDataContent)
{
insertFirstToDatabase(line,vo); --just this is different.
}
}
second one is :
inputStreamReader = new InputStreamReader(new FileInputStream(FileTwo),"gbk");
--different place
br=new BufferedReader(inputStreamReader);
lineNumber = 0;
boolean isDataContent = false;
while (br.ready()) {
String line = br.readLine();
if(line == null){
continue;
}
if(line.contains("<lineNumber>"))
{
try {
lineNumber = Integer.parseInt( StringTools.getDigitalInString(line));
} catch (NumberFormatException e) {
log.error("there is no lineNumber");
}
continue;
}
if(line.trim().equals("<begin>"))
{
isDataContent = true;
continue;
}
if(line.trim().equals("<end>"))
{
break;
}
if(isDataContent)
{
insertSecondToDatabase(line,vo); --only this is different.
}
}
The two piece of code is in two different service code. How can I refactor this reduplicate code? so that each place Just only call one same function to check the lineNumber.
Have the duplicated code in a class that both the other classes either inherit (inheritance) or include a copy of (composition). Alternatively you could even make it a static method in a utility class.
Your code is identical until a single statement, and it's not shown how you determined which of these sequences of code you should be executing, but just move that branching into the if (isDataContent):
// copy/paste from your own, change the if to:
if(isDataContent) {
if (flagFirst) {
insertFirstToDatabase(line,vo); --just this is different.
} else {
insertSecondToDatabase(line,vo); --only this is different.
}
}
Where flagFirst is either a boolean variable or a boolean expression to determine which of the inserts should be done.
You can add 'kind' parameter for selecting usded inserting method as following:
public void process(int kind) {
....
while (br.ready()) {
String line = br.readLine();
if(line == null){
continue;
}
if(line.contains("<lineNumber>"))
{
try {
lineNumber = Integer.parseInt( StringTools.getDigitalInString(line));
} catch (NumberFormatException e) {
log.error("there is no lineNumber");
}
continue;
}
if(line.trim().equals("<begin>"))
{
isDataContent = true;
continue;
}
if(line.trim().equals("<end>"))
{
break;
}
if(isDataContent)
{
if (kind == 1) {
insertFirstToDatabase(line,vo); --just this is different.
}
if (kind == 2) {
insertSecondToDatabase(line,vo); --only this is different.
}
}
}
}
2 things:
duplicated code? - put in static method in utility class
how to differentiate dataContent? -
i. this can be determined while parsing the line depending on the order of fields
(or)
ii. the callee of the static method can determine the same by sending a flag. But this is not good design. You are placing too much implementation i.e. 2 behaviors in a utility method.
(or)
iii. Let the static method parse the XML and return just the line details to the callee. Let the callee handle however it likes. First callee might just want to print, second callee might want to put into db.
So, here it goes,
public static LineDetails parseXML(String filename)
{
inputStreamReader = new InputStreamReader(new FileInputStream(new File(filename));
br=new BufferedReader(inputStreamReader);
lineNumber = 0;
boolean isDataContent = false;
LineDetails lineDetails = new LineDetails();
while (br.ready()) {
String line = br.readLine();
if(line == null){
continue;
}
if(line.contains("<lineNumber>"))
{
try {
lineNumber = Integer.parseInt( StringTools.getDigitalInString(line));
} catch (NumberFormatException e) {
log.error("there is no lineNumber");
}
lineDetails.setLineNumber(lineNumber);
continue;
}
if(line.trim().equals("<begin>"))
{
isDataContent = true;
continue;
}
if(line.trim().equals("<end>"))
{
break;
}
if(isDataContent)
{
// parse line
lineDetails.setLine(line);
}
}
return lineDetails;
}
public class LineDetails
{
private int lineNumber=0;
private String line="";
// getters setters
}
//First callee
methodA()
{
LineDetails lineDetails = parseXML(filename);
if(lineDetails!=null && lineDetails.getLineNumber==19 && lineDetails.getLine()!=null && !lineDetails.getLine.equals(""))
{
insertFirstToDatabase(line);
}
}
//Second callee
methodB()
{
LineDetails lineDetails = parseXML(filename);
if(lineDetails!=null && lineDetails.getLineNumber==27 && lineDetails.getLine()!=null && !lineDetails.getLine.equals(""))
{
insertSecondToDatabase(line);
}
}
I am trying to do autocomplete when I type in characters in ice:selectInputText
Issue I am facing is when I type in characters it brings even names which is not matching with the characters I type.
See the below screen shot for reference.
Ideally autocomplete should display only the first row from the result, however it displays rows which are not matching my typed characters.
Only Abell Maryland 20606 should display.
This is the code which is using for the comparison, how can I modify this to suit to my requirement which is to display only those results which is matching to what I type.
public int compare(Object o1, Object o2) {
if (o1 instanceof SelectItem) {
s1 = ((SelectItem) o1).getLabel();
} else {
s1 = o1.toString();
}
if (o2 instanceof SelectItem) {
s2 = ((SelectItem) o2).getLabel();
} else {
s2 = o2.toString();
}
return s1.compareToIgnoreCase(s2);
}
};
I am following this tutorial from Icefaces
http://wiki.icefaces.org/display/ICE/Auto-Complete
Update
My code in autocomplete.jspx
<ice:selectInputText rows="10" width="300"
listVar="emp"
valueChangeListener="#{mybean.updateList}"
listValue="#{mybean.list}">
<f:facet name="selectInputText">
<ice:panelGrid columns="3" columnClasses="empNameCol">
<ice:outputText value="#{emp.empName}"/>
</ice:panelGrid>
method updateList
public void updateList(ValueChangeEvent event) {
setMatches(event);
if (event.getComponent() instanceof SelectInputText) {
SelectInputText autoComplete = (SelectInputText)event.getComponent();
if (autoComplete.getSelectedItem() != null) {
bean = (Bean)autoComplete.getSelectedItem().getValue();
}
else {
Bean tempCity = getMatch(autoComplete.getValue().toString());
if (tempCity != null) {
bean = tempCity;
}
}
}
}
Method setMatches
private void setMatches(ValueChangeEvent event) {
Object searchWord = event.getNewValue();
int maxMatches = ((SelectInputText)event.getComponent()).getRows();
List matchList = new ArrayList(maxMatches);
try {
int insert =
Collections.binarySearch(dictionary, searchWord, AutoCompleteDictionary.LABEL_COMPARATOR);
if (insert < 0) {
insert = Math.abs(insert) - 1;
}
for (int i = 0; i < maxMatches; i++) {
if ((insert + i) >= dictionary.size() || i >= maxMatches) {
break;
}
matchList.add(dictionary.get(insert + i));
}
} catch (Throwable e) {
e.printStackTrace();
logger.error("Erorr finding autocomplete matches" + e.getMessage());
}
if (this.matchesList != null) {
this.matchesList.clear();
this.matchesList = null;
}
this.matchesList = matchList;
}
Update 2
Modified setMatches method
private void setMatches(ValueChangeEvent event) {
Object searchWord = event.getNewValue();
int maxMatches = ((SelectInputText) event.getComponent()).getRows();
List matchList = new ArrayList(maxMatches);
try {
for(int i = 0; i < dictionary.size(); i++) {
SelectItem s = (SelectItem)dictionary.get(i);
if(s.getLabel().startsWith(searchWord.toString())) {
matchList.add(s);
if(matchList.size() == maxMatches)
break;
}
}
} catch (Throwable e) {
e.printStackTrace();
logger.error("Erorr finding autocomplete matches" + e.getMessage());
}
if (this.matchesList != null) {
this.matchesList.clear();
this.matchesList = null;
}
this.matchesList = matchList;
}
You have to update the list of SelectItems. Instead of just odering the list you have to filter the list (or creating a new one which only contains the matches). The next time the autocomplete-list renders it will evaluate the bound list again.
The tutorial of icefaces has some sources attached (bottom). Take a look at AutoCompleteBean . The method updateList(ValueChangeEvent e) calls setMatches(e). Within this method the list is assigned with a new one.
// assign new matchList
if (this.matchesList != null) {
this.matchesList.clear();
this.matchesList = null;
}
this.matchesList = matchList;
This causes the ui component to show only items which match the input.
To sum it up: ice:selectInputList will always show the items contained in its list, so reduce the items in the list to show the relevant ones only.
Regards
Update
private void setMatches(ValueChangeEvent event) {
Object searchWord = event.getNewValue();
int maxMatches = ((SelectInputText)event.getComponent()).getRows();
List matchList = new ArrayList(maxMatches);
try {
for(int i = 0; i < dictionary.size(); i++) {
SelectItem s = dictionary.get(i);
if(s.getLabel().startsWith(searchWord)) {
matchList.add(s);
if(matchList.size() == maxMatches)
break;
}
}
} catch (Throwable e) {
e.printStackTrace();
logger.error("Erorr finding autocomplete matches" + e.getMessage());
}
if (this.matchesList != null) {
this.matchesList.clear();
this.matchesList = null;
}
this.matchesList = matchList;
}
// note: not optimized, just to explain how to do.
Update 2 (short version)
/**
* Fills the suggestionList with the given luceneResult.
*
* #param suggestionList The list to fill.
* #param luceneResult The previously computed luceneResult.
*/
private static void fillLookupSuggestionList(final List<SelectItem> suggestionList,
LuceneResult luceneResult)
{
suggestionList.clear();
String searchQuery = luceneResult.getLuceneResultConfig().getSearchQuery();
if (luceneResult.getResultSize() <= 0)
{
suggestionList.add(new SelectItem(null, BundleHelper.i18n(LuceneLookupController.BUNDLE,
LuceneLookupController.NO_ITEM_FOUND)));
}
else
{
List<LuceneResultEntry> results = luceneResult.getResult();
for (LuceneResultEntry entry : results)
{
suggestionList.add(new SelectItem(entry.getMetaInfo(),
entry.getInfo().getDescription()));
}
}
}