SMPP error code 61,62 - smpp

I am using the jsmpp lib for sending sms. The SMSC center returns negative response like 61,62 which are Invalid scheduled delivery time and Invalid Validty Period value. After talking with SMSC support, they require to set a default timeout for the message to be delivered, after some search on jsmpp site, didn't find it. Thanks for any suggestions ?

According to SMPP standard it should be possible to leave both of these null, but if Validity Period is required, this can be either an absolute date or a relative one.
The format should be YYMMDDhhmmsstnnp, where
YY is a two digit year (00-99)
MM is month (01-12)
DD is day (01-31)
hh is hours (00-23)
mm is minutes (00-59)
ss is seconds (00-59)
t is tenths of second (00-59)
nn is the time difference in quarter hours between local time and UTC (00-48)
p can be one of the following :-
'+' local time is ahead of UTC.
'-' local time is behind UTC.
'R' This is a relative time.
So to make the validity period 1 hour using a relative time use the following: "000000010000000R"

In my project I didn't have business requirement to schedule delivery time and set validity Period, so I set them null and it's work fine :-)
I use this class to load smpp config from properties file. Code that will using it will looks more readable and simple :-)
SMPPConfigManager is an interface for this class. It's possible to read this config not only from properties file. For example from Db and you can then implement this interface in new class.
package ru.rodin.denis.smpp;
import java.util.Properties;
import org.jsmpp.bean.*;
/**
*
* #author Denis Rodin
*/
public class SMPPFileConfig implements SMPPConfigManager {
private String host;
private int port;
private String systemId;
private String password;
private String systemType;
private TypeOfNumber sourceAddrTon;
private TypeOfNumber destAddrTon;
private NumberingPlanIndicator sourceAddrNpi;
private NumberingPlanIndicator destAddrNpi;
private String addressRange;
private int connectTimeout;
private long reconnectInterval;
private String sourceAddr;
private String destinationAddr;
private SMSCDeliveryReceipt deliveryReceipt;
private RegisteredDelivery registeredDelivery;
private BindType bindType;
private ESMClass esmClass;
private byte protocolId;
private byte priorityFlag;
private String scheduleDeliveryTime;
private String validityPeriod;
private byte replaceIfPresentFlag;
private GeneralDataCoding generalDataCoding;
private boolean generalDataCoding_compressed = true;
private boolean generalDataCoding_containMessageClass = true;
private MessageClass generalDataCoding_messageClass = MessageClass.CLASS1;
private Alphabet generalDataCoding_alphabet = Alphabet.ALPHA_DEFAULT;
private byte smDefaultMsgId;
private long transactionTimer;
private int enquireLinkTimer;
public SMPPFileConfig(Properties prop) {
this.host = prop.getProperty("smpp.host");
this.port = Integer.parseInt(prop.getProperty("smpp.port"));
this.systemId = prop.getProperty("smpp.systemId");
this.password = prop.getProperty("smpp.password");
this.systemType = prop.getProperty("smpp.systemType");
this.sourceAddrTon = getTypeOfNumber(SMPPConfigManager.AddrTon.SOURCE, prop);
this.destAddrTon = getTypeOfNumber(SMPPConfigManager.AddrTon.DEST, prop);
this.sourceAddrNpi = getNumberingPlanIndicator(SMPPConfigManager.AddrNpi.SOURCE, prop);
this.destAddrNpi = getNumberingPlanIndicator(SMPPConfigManager.AddrNpi.DEST, prop);
this.addressRange = prop.getProperty("smpp.addressRange");
this.connectTimeout = Integer.parseInt(prop.getProperty("smpp.connect.timeout"));
this.reconnectInterval = Long.parseLong(prop.getProperty("smpp.reconnect.interval"));
this.sourceAddr = prop.getProperty("smpp.sourceAddr");
this.destinationAddr = null;
this.deliveryReceipt = getSMSCDeliveryReceipt(prop.getProperty("smpp.SMSC.delivery.receipt"));
this.registeredDelivery = new RegisteredDelivery(deliveryReceipt);
this.bindType = getBindTypeFromProp(prop.getProperty("smpp.bindType"));
this.esmClass = createESMClass(prop.getProperty("smpp.ESMClass.MessageMode"), prop.getProperty("smpp.ESMClass.MessageType"), prop.getProperty("smpp.ESMClass.GSMSpecificFeature"));
this.protocolId = new Byte(prop.getProperty("smpp.protocolId"));
this.priorityFlag = new Byte(prop.getProperty("smpp.priorityFlag"));
this.scheduleDeliveryTime = prop.getProperty("smpp.scheduleDeliveryTime");
this.validityPeriod = prop.getProperty("smpp.validityPeriod");
this.replaceIfPresentFlag = new Byte(prop.getProperty("smpp.replaceIfPresentFlag"));
this.generalDataCoding = new GeneralDataCoding(generalDataCoding_compressed, generalDataCoding_containMessageClass, generalDataCoding_messageClass, generalDataCoding_alphabet);
this.smDefaultMsgId = new Byte(prop.getProperty("smpp.smDefaultMsgId"));
this.transactionTimer = Long.parseLong(prop.getProperty("smpp.transactionTimer"));
this.enquireLinkTimer = Integer.parseInt(prop.getProperty("smpp.enquireLinkTimer"));
}
#Override
public String toString() {
return "SMPPFileConfig{" + "host=" + host + ", port=" + port + ", systemId=" + systemId + ", password=" + password + ", systemType=" + systemType + ", sourceAddrTon=" + sourceAddrTon + ", destAddrTon=" + destAddrTon + ", sourceAddrNpi=" + sourceAddrNpi + ", destAddrNpi=" + destAddrNpi + ", addressRange=" + addressRange + ", connectTimeout=" + connectTimeout + ", reconnectInterval=" + reconnectInterval + ", sourceAddr=" + sourceAddr + ", destinationAddr=" + destinationAddr + ", deliveryReceipt=" + deliveryReceipt + ", registeredDelivery=" + registeredDelivery + ", bindType=" + bindType + ", esmClass=" + esmClass + ", protocolId=" + protocolId + ", priorityFlag=" + priorityFlag + ", scheduleDeliveryTime=" + scheduleDeliveryTime + ", validityPeriod=" + validityPeriod + ", replaceIfPresentFlag=" + replaceIfPresentFlag + ", generalDataCoding=" + generalDataCoding + ", generalDataCoding_compressed=" + generalDataCoding_compressed + ", generalDataCoding_containMessageClass=" + generalDataCoding_containMessageClass + ", generalDataCoding_messageClass=" + generalDataCoding_messageClass + ", generalDataCoding_alphabet=" + generalDataCoding_alphabet + ", smDefaultMsgId=" + smDefaultMsgId + '}';
}
#Override
public String getAddressRange() {
return addressRange;
}
#Override
public int getConnectTimeout() {
return connectTimeout;
}
#Override
public SMSCDeliveryReceipt getDeliveryReceipt() {
return deliveryReceipt;
}
#Override
public RegisteredDelivery getRegisteredDelivery() {
return registeredDelivery;
}
#Override
public NumberingPlanIndicator getDestAddrNpi() {
return destAddrNpi;
}
#Override
public TypeOfNumber getDestAddrTon() {
return destAddrTon;
}
#Override
public void setDestinationAddr(String destinationAddr) {
this.destinationAddr = destinationAddr;
}
#Override
public String getDestinationAddr() {
return destinationAddr;
}
#Override
public String getHost() {
return host;
}
#Override
public String getPassword() {
return password;
}
#Override
public int getPort() {
return port;
}
#Override
public long getReconnectInterval() {
return reconnectInterval;
}
#Override
public String getSourceAddr() {
return sourceAddr;
}
#Override
public NumberingPlanIndicator getSourceAddrNpi() {
return sourceAddrNpi;
}
#Override
public TypeOfNumber getSourceAddrTon() {
return sourceAddrTon;
}
#Override
public String getSystemId() {
return systemId;
}
#Override
public String getSystemType() {
return systemType;
}
#Override
public BindType getBindType() {
return bindType;
}
#Override
public ESMClass getESMClass() {
return esmClass;
}
#Override
public void setESMClass(ESMClass esmClass) {
this.esmClass = esmClass;
}
#Override
public byte getProtocolId() {
return protocolId;
}
#Override
public byte getPriorityFlag() {
return priorityFlag;
}
#Override
public String getScheduleDeliveryTime() {
return scheduleDeliveryTime;
}
#Override
public String getValidityPeriod() {
return validityPeriod;
}
#Override
public byte getReplaceIfPresentFlag() {
return replaceIfPresentFlag;
}
#Override
public GeneralDataCoding getGeneralDataCoding() {
return generalDataCoding;
}
#Override
public byte getsmDefaultMsgId(){
return smDefaultMsgId;
}
#Override
public long getTransactionTimer()
{
return transactionTimer;
}
#Override
public int getEnquireLinkTimer()
{
return enquireLinkTimer;
}
private ESMClass createESMClass(String messageMode, String messageType, String GSMSpecificFeature) {
return new ESMClass(getESMClassMessageMode(messageMode), getESMMessageType(messageType), getESMGSMSpecificFeature(GSMSpecificFeature));
}
private MessageMode getESMClassMessageMode(String type) {
if (type.equals("DEFAULT")) {
return MessageMode.DEFAULT;
} else if (type.equals("DATAGRAM")) {
return MessageMode.DATAGRAM;
} else if (type.equals("STORE_AND_FORWARD")) {
return MessageMode.STORE_AND_FORWARD;
} else if (type.equals("TRANSACTION")) {
return MessageMode.TRANSACTION;
} else {
return null;
}
}
private MessageType getESMMessageType(String type) {
if (type.equals("DEFAULT")) {
return MessageType.DEFAULT;
} else if (type.equals("CONV_ABORT")) {
return MessageType.CONV_ABORT;
} else if (type.equals("ESME_DEL_ACK")) {
return MessageType.ESME_DEL_ACK;
} else if (type.equals("ESME_MAN_ACK")) {
return MessageType.ESME_MAN_ACK;
} else if (type.equals("INTER_DEL_NOTIF")) {
return MessageType.INTER_DEL_NOTIF;
} else if (type.equals("SME_DEL_ACK")) {
return MessageType.SME_DEL_ACK;
} else if (type.equals("SME_MAN_ACK")) {
return MessageType.SME_MAN_ACK;
} else if (type.equals("SMSC_DEL_RECEIPT")) {
return MessageType.SMSC_DEL_RECEIPT;
} else {
return null;
}
}
private GSMSpecificFeature getESMGSMSpecificFeature(String type) {
if (type.equals("DEFAULT")) {
return GSMSpecificFeature.DEFAULT;
} else if (type.equals("REPLYPATH")) {
return GSMSpecificFeature.REPLYPATH;
} else if (type.equals("UDHI")) {
return GSMSpecificFeature.UDHI;
} else if (type.equals("UDHI_REPLYPATH")) {
return GSMSpecificFeature.UDHI_REPLYPATH;
} else {
return null;
}
}
private BindType getBindTypeFromProp(String type) {
//String type = prop.getProperty("smpp.bindType");
if (type.equals("BIND_RX")) {
return BindType.BIND_RX;
} else if (type.equals("BIND_TX")) {
return BindType.BIND_TX;
} else if (type.equals("BIND_TRX")) {
return BindType.BIND_TRX;
} else {
return null;
}
}
private TypeOfNumber getTypeOfNumber(SMPPConfigManager.AddrTon ton, Properties prop) {
String type;
if (ton == SMPPConfigManager.AddrTon.SOURCE) {
type = prop.getProperty("smpp.sourceAddrTon");
} else {
type = prop.getProperty("smpp.destAddrTon");
}
if (type.equals("ABBREVIATED")) {
return TypeOfNumber.ABBREVIATED;
} else if (type.equals("ALPHANUMERIC")) {
return TypeOfNumber.ALPHANUMERIC;
} else if (type.equals("INTERNATIONAL")) {
return TypeOfNumber.INTERNATIONAL;
} else if (type.equals("NATIONAL")) {
return TypeOfNumber.NATIONAL;
} else if (type.equals("NETWORK_SPECIFIC")) {
return TypeOfNumber.NETWORK_SPECIFIC;
} else if (type.equals("SUBSCRIBER_NUMBER")) {
return TypeOfNumber.SUBSCRIBER_NUMBER;
} else if (type.equals("UNKNOWN")) {
return TypeOfNumber.UNKNOWN;
} else {
return null;
}
}
private SMSCDeliveryReceipt getSMSCDeliveryReceipt(String type) {
//String type = prop.getProperty("smpp.SMSC.delivery.receipt");
if (type.equals("DEFAULT")) {
return SMSCDeliveryReceipt.DEFAULT;
} else if (type.equals("SUCCESS")) {
return SMSCDeliveryReceipt.SUCCESS;
} else if (type.equals("SUCCESS_FAILURE")) {
return SMSCDeliveryReceipt.SUCCESS_FAILURE;
} else {
return null;
}
}
private NumberingPlanIndicator getNumberingPlanIndicator(SMPPConfigManager.AddrNpi npi, Properties prop) {
String type;
if (npi == SMPPConfigManager.AddrNpi.SOURCE) {
type = prop.getProperty("smpp.sourceAddrNpi");
} else {
type = prop.getProperty("smpp.destAddrNpi");
}
if (type.equals("DATA")) {
return NumberingPlanIndicator.DATA;
} else if (type.equals("ERMES")) {
return NumberingPlanIndicator.ERMES;
} else if (type.equals("INTERNET")) {
return NumberingPlanIndicator.INTERNET;
} else if (type.equals("ISDN")) {
return NumberingPlanIndicator.ISDN;
} else if (type.equals("LAND_MOBILE")) {
return NumberingPlanIndicator.LAND_MOBILE;
} else if (type.equals("NATIONAL")) {
return NumberingPlanIndicator.NATIONAL;
} else if (type.equals("PRIVATE")) {
return NumberingPlanIndicator.PRIVATE;
} else if (type.equals("TELEX")) {
return NumberingPlanIndicator.TELEX;
} else if (type.equals("WAP")) {
return NumberingPlanIndicator.WAP;
} else if (type.equals("UNKNOWN")) {
return NumberingPlanIndicator.UNKNOWN;
} else {
return null;
}
}
}

when you submit current time as scheduled delivery time this error may occur.because it takes some time to send request. so the time you mentioned might be in past .so set the scheduled delivery time to (current time + 10 seconds )
long TEN_SECONDS=10000;//millisecs
Calendar date = Calendar.getInstance();
long t= date.getTimeInMillis();
Date scheduleDeliveryTime=new Date(t + ( TEN_SECONDS));

Related

Java.lang.String errors & not printing to error file

For this project the end result was for there to be 2 error reports sent to an error file at as well as a listing of account summary information printed out. While i can get a majority of the account information printed out such as Balance before transaction and transaction to the account or if there were insufficient funds for the transaction, that's all that will print out as it should be. I'm receiving no errors or exceptions so i'm in all honesty not too sure where the issue at hand may be. I was hoping a second pair of eyes on my code could possibly point out where my issue may be, below is my code of the Account.java, CheckingAccount.java CreditCard.java and lastly D4.java which contains the main method.
Account.java
public class Account {
protected String accountNo, institution, name;
protected double balance;
public Account (String accountNo, String name, String institution, double balance) {
this.name = name;
this.accountNo = accountNo;
this.balance = balance;
this.institution = institution;
}
public String getAccount() {
return accountNo;
}
public boolean debitAccount(double amt) {
return false;
}
public boolean creditAccount(double amt) {
return false;
}
}
CheckingAccount.java
public class CheckingAccount extends Account {
public CheckingAccount(String acctNo, String name, String inst, double balance) {
super(acctNo, name, inst, balance);
this.name = name;
this.accountNo = acctNo;
this.balance = balance;
this.institution = institution;
}
public double getBalance()
{
return balance;
}
public boolean debitAccount(double amt) {
balance += amt;
return false;
}
public boolean creditAccount(double amt) {
balance -= amt;
return false;
}
}
CreditCard.java
public class CreditCard extends Account {
private double creditLimit;
private double availableCredit;
public CreditCard(String acctNo, String name, String inst, double limit, double balance) {
super(acctNo, name, inst, 0);
this.creditLimit = creditLimit;
this.availableCredit = availableCredit;
this.balance = balance;
}
public boolean debitAccount(double amt) {
balance -= amt;
return false;
}
public double getCreditLimit(){
return creditLimit;
}
public double getBalance()
{
return balance;
}
public boolean creditAccount(double amt) {
balance += amt;
return false;
}
}
D4.java
import java.io.*;
import java.util.*;
public class D4 {
public static void main(String[] args) throws FileNotFoundException
{
Boolean valid;
String transactionFile = args[0];
String theaccount, transaction;
File transactions = new File(transactionFile);
Scanner infile = new Scanner(transactions);
File errorFile = new File(args[1]);
PrintWriter error = new PrintWriter(errorFile);
Vector<Account> account = new Vector<Account>();
while(infile.hasNext())
{
transaction = infile.nextLine();
valid = performTrans(account, transaction, error, errorFile);
}
}
private static Account findAccount(Vector<Account> a, String acctNo) {
for(int index = 0; index < a.size(); index ++)
{
if (a.elementAt(index).getAccount().equals(acctNo))
{
return a.elementAt(index);
}
}
return null;
}
private static boolean Checkingacct(Account a)
{
if(a instanceof CheckingAccount)
{
return true;
}
else
{
return false;
}
}
private static boolean Creditcrd(Account a)
{
if(a instanceof CreditCard)
{
return true;
}
else
{
return false;
}
}
private static String errorLog(Vector<Account> a, String transaction)
{
String[] trans = transaction.split(":");
String error;
if(findAccount(a, trans[1])==null)
{
error = ("Invalid account: " + transaction);
System.out.println(error);
return error;
}
else
{
Account acc = findAccount(a, trans[1]);
if( trans[0] == "debit")
{
error = ("Transaction denied: " + transaction);
System.out.println(error);
return error;
}
else
{
return null;
}
}
}
private static boolean performTrans(Vector<Account> account, String transaction, PrintWriter log, File errorFile)
{
String[] pieces = transaction.split(":");
String trans = pieces[0];
System.out.println(pieces);
if(trans.equals("create"))
{
if( pieces[1].equals("checking"))
{
CheckingAccount checking = new CheckingAccount(pieces[2], pieces[3], pieces[4], Double.parseDouble(pieces[5]));
account.add(checking);
return true;
}
else if (pieces[1].equals("credit"))
{
CreditCard creditCard = new CreditCard(pieces[2], pieces[3], pieces[4], 0, Double.parseDouble(pieces[5]));
account.add(creditCard);
return true;
}
else
{
System.out.println("not sure what to put here");
return false;
}
}
else if(trans.equals("debit"))
{
if(findAccount(account, pieces[1]) == null)
{
return false;
}
else
{
Account a = findAccount(account, pieces[1]);
double amount = Double.parseDouble(pieces[2]);
if(Checkingacct(a) == true)
{
CheckingAccount checking = (CheckingAccount) a;
System.out.println("Balance before transaction: " + checking.getBalance());
checking.creditAccount(amount);
System.out.println("Transaction to account: " + amount);
System.out.println("Balance after transaction: " + checking.getBalance() + "\n");
return true;
}
else if(Creditcrd(a) == true)
{
CreditCard creditCard = (CreditCard) a;
System.out.println("Balance before transaction: " + creditCard.getBalance());
System.out.println("Transaction to account: " + amount);
if(amount + creditCard.getBalance() > creditCard.getCreditLimit())
{
System.out.println("Insufficient funds for transaction");
return false;
}
else
{
creditCard.creditAccount(amount);
return true;
}
}
}
}
else if(trans.equals("credit"))
{
if(findAccount(account, pieces[1]) == null)
{
System.out.println("Print Error Message");
return false;
}
else
{
Account a = findAccount(account, pieces[1]);
double amount = Double.parseDouble(pieces[2]);
if(Creditcrd(a) == true)
{
CheckingAccount checking = (CheckingAccount) a;
System.out.println("Balance before transaction: " + checking.getBalance());
checking.debitAccount(amount);
System.out.println("Transaction to account: " + amount);
System.out.println("Balance after transaction: " + checking.getBalance() + "\n");
return true;
}
else if(Creditcrd(a) == true)
{
CreditCard creditCard = (CreditCard) a;
System.out.println(creditCard.getBalance());
return true;
}
}
}
else if(trans.equals("report"))
{
return true;
}
return false;
}
}
The text file im attempting to read from is called D4.txt and the information inside of it is
create:checking:10-3784665:Chase:Joe Holder:2000
create:credit:1234567898765432:First Card:Bob Badger:4000
create:checking:11-3478645:Dime:Melissa Martin:1000
report
debit:10-3784665:523.67
debit:1234567898765432:3500
credit:10-3784665:50
credit:11-3478645:30
debit:10-839723:200
debit:1234567898765432:600
report
The two errors im supposed to be able to print out and see in the errorFile.txt or whatever you choose to call it is and is where the main problem is as this information for some reason is not being processed and printed onto the outputfle.
Invalid account: debit:10839723:200
Transaction denied: debit:1234567898765432:600
The information printed to the console is supposed to look like
Account Summary:
Checking account #103784665
Bank: Chase
Name on account: Joe Holder
Balance: 1526.33
Credit Account #1234567898765432
Bank: First Card
Issued to: Bob Badger
Credit Limit: 4000
Balance: 3500.00
Available credit: 500.00
Checking account #113478645
Bank: Dime
Name on account: Melissa Martin
Balance: 1030.00
End account summary.
But this is also a part of the issue as currently when i run the code whats being printed out to the console is
run D4 d4.txt errorFile.txt
[Ljava.lang.String;#1d540a51
[Ljava.lang.String;#b31c562
[Ljava.lang.String;#3db12bab
[Ljava.lang.String;#4ff0c6b8
[Ljava.lang.String;#4d40d320
Balance before transaction: 2000.0
Transaction to account: 523.67
Balance after transaction: 1476.33
[Ljava.lang.String;#2c9cc42e
Balance before transaction: 4000.0
Transaction to account: 3500.0
Insufficient funds for transaction
[Ljava.lang.String;#2bb07c61
[Ljava.lang.String;#483b594b
[Ljava.lang.String;#31470572
[Ljava.lang.String;#20aedee
Balance before transaction: 4000.0
Transaction to account: 600.0
Insufficient funds for transaction
[Ljava.lang.String;#2ea4aa4d
I know this is a lot of information to sort through and i just want to thank anyone and everyone in advance for your help and hope its something simple that im just overlooking!

How to deserialize a JSON object to a binary tree by using Jackson

From the previous question How to deserialize a JSON array to a singly linked list , I learned how to deserialize a JSON array to a singly linked list.
Now I want to deserialize a JSON object to a binary tree in Java.
The definition of the binary tree node is as the following:
public class BinaryTreeNode<E> {
public E value;
public BinaryTreeNode left;
public BinaryTreeNode right;
public BinaryTreeNode(final E value) {
this.value = value;
}
}
How to deserialize a JSON string such as:
{
"value": 2,
"left": {
"value": 1,
"left": null,
"right": null
},
"right": {
"value": 10,
"left": {
"value": 5,
"left": null,
"right": null
},
"right": null
}
}
to a binary tree?
2
/ \
1 10
/
5
Here is the unit test code:
#Test public void binaryTreeNodeTest() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
final ArrayList<Integer> intArray = objectMapper.readValue("[1,2,3,4,5]",
new TypeReference<ArrayList<Integer>>() {});
System.out.println(intArray);
/* How to achieve this?
2
/ \
1 10
/
5
{
"value": 2,
"left": {
"value": 1,
"left": null,
"right": null
},
"right": {
"value": 10,
"left": {
"value": 5,
"left": null,
"right": null
},
"right": null
}
}
*/
final String jsonStr = "{\n"
+ " \"value\": 2,\n"
+ " \"left\": {\n"
+ " \"value\": 1,\n"
+ " \"left\": null,\n"
+ " \"right\": null\n"
+ " },\n" + " \"right\": {\n"
+ " \"value\": 10,\n"
+ " \"left\": {\n"
+ " \"value\": 5,\n"
+ " \"left\": null,\n"
+ " \"right\": null\n"
+ " },\n"
+ " \"right\": null\n"
+ " }\n"
+ "}";
System.out.println(jsonStr);
final BinaryTreeNode<Integer> intTree = objectMapper.readValue(jsonStr,
new TypeReference<BinaryTreeNode<Integer>>() {});
System.out.println(intTree);
}
In other word, I want the BinaryTreeNode to be a first-class citizen the same as ArrayList, which can be used in all kinds of combinations, such as HashSet<BinaryTreeNode<Integer>>, BinaryTreeNode<HashMap<String, Integer>>, etc.
The solution is quite simple, since JSON can express tree naturally, Jackson can deal with recursive tree directly. Just annotate a constructor with JsonCreator:
public static class BinaryTreeNode<E>
{
public E value;
public BinaryTreeNode left;
public BinaryTreeNode right;
#JsonCreator
public BinaryTreeNode(#JsonProperty("value") final E value) {
this.value = value;
}
}
Let's write a unite test to try it:
package me.soulmachine.customized_collection;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class BinaryTreeNodeTest {
public static class BinaryTreeNode<E> {
public E value;
public BinaryTreeNode left;
public BinaryTreeNode right;
#JsonCreator
public BinaryTreeNode(#JsonProperty("value") final E value) {
this.value = value;
}
ArrayList<E> preOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
preOrder(this, result);
return result;
}
private static <E> void preOrder(BinaryTreeNode<E> root, ArrayList<E> result) {
if (root == null)
return;
result.add(root.value);
if (root.left != null)
preOrder(root.left, result);
if (root.right != null)
preOrder(root.right, result);
}
}
#Test public void binaryTreeNodeTest() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
/*
2
/ \
1 10
/
5
*/
final String jsonStr = "{\n"
+ " \"value\": 2,\n"
+ " \"left\": {\n"
+ " \"value\": 1,\n"
+ " \"left\": null,\n"
+ " \"right\": null\n"
+ " },\n" + " \"right\": {\n"
+ " \"value\": 10,\n"
+ " \"left\": {\n"
+ " \"value\": 5,\n"
+ " \"left\": null,\n"
+ " \"right\": null\n"
+ " },\n"
+ " \"right\": null\n"
+ " }\n"
+ "}";
System.out.println(jsonStr);
final BinaryTreeNode<Integer> intTree = objectMapper.readValue(jsonStr,
new TypeReference<BinaryTreeNode<Integer>>() {});
final List<Integer> listExpected = Arrays.asList(2, 1, 10, 5);
assertEquals(listExpected, intTree.preOrder());
}
}
A compact serialization format
Well, there is a little problem here, the JSON string above is very verbose. Let's use another kind of serialization format, i.e., serialize a binary tree in level order traversal. For example, the binary tree above can be serialized as the following JSON string:
[2,1,10,null,null,5]
Now how to deserialize this JSON string to a binary tree?
The idea is very similar to my previous article, Deserialize a JSON Array to a Singly Linked List. Just make the BinaryTreeNode implement java.util.list, pretend that it's a list, write our own deserialization code so that Jackson can treat a binary tree as a list.
The complete code of BinaryTreeNode is as the following:
package me.soulmachine.customized_collection;
import java.util.*;
public class BinaryTreeNode<E> extends AbstractSequentialList<E>
implements Cloneable, java.io.Serializable {
public E value;
public BinaryTreeNode<E> left;
public BinaryTreeNode<E> right;
/** has a left child, but it's a null node. */
private transient boolean leftIsNull;
/** has a right child, but it's a null node. */
private transient boolean rightIsNull;
/**
* Constructs an empty binary tree.
*/
public BinaryTreeNode() {
value = null;
left = null;
right = null;
}
/**
* Constructs an binary tree with one element.
*/
public BinaryTreeNode(final E value) {
if (value == null) throw new IllegalArgumentException("null value");
this.value = value;
left = null;
right = null;
}
/**
* Constructs a binary tree containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* #param c the collection whose elements are to be placed into this binary tree
* #throws NullPointerException if the specified collection is null
*/
public BinaryTreeNode(Collection<? extends E> c) {
this();
addAll(c);
}
/**
* #inheritDoc
*
* <p>Note: null in the middle counts, so that each father in the binary tree has a
* one-to-one mapping with the JSON array.</p>
*/
public int size() {
if (value == null) return 0;
Queue<BinaryTreeNode<E>> queue = new LinkedList<>();
queue.add(this);
int count = 0;
while (!queue.isEmpty()) {
final BinaryTreeNode<E> node = queue.remove();
++count;
if (node.left != null) {
queue.add(node.left);
} else {
if (node.leftIsNull) ++count;
}
if (node.right != null) {
queue.add(node.right);
} else {
if (node.rightIsNull) ++count;
}
}
return count;
}
/**
* Tells if the argument is the index of a valid position for an
* iterator or an add operation.
*/
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size();
}
/**
* Constructs an IndexOutOfBoundsException detail message.
* Of the many possible refactorings of the error handling code,
* this "outlining" performs best with both server and client VMs.
*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+ size();
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private class NodeAndFather {
private BinaryTreeNode<E> node;
private BinaryTreeNode<E> father;
private boolean isRight; // the father is the right child of the father
private NodeAndFather(BinaryTreeNode<E> node, BinaryTreeNode<E> father, boolean isRight) {
this.node = node;
this.father = father;
this.isRight = isRight;
}
}
/**
* Returns the (may be null) Node at the specified element index.
*/
NodeAndFather node(int index) {
checkPositionIndex(index);
if (value == null) return null;
Queue<NodeAndFather> queue = new LinkedList<>();
queue.add(new NodeAndFather(this, null, false));
for (int i = 0; !queue.isEmpty(); ++i) {
final NodeAndFather nodeAndFather = queue.remove();
if ( i == index) {
return nodeAndFather;
}
if (nodeAndFather.node != null) {
queue.add(new NodeAndFather(nodeAndFather.node.left, nodeAndFather.node, false));
queue.add(new NodeAndFather(nodeAndFather.node.right, nodeAndFather.node, true));
}
}
throw new IllegalArgumentException("Illegal index: " + index);
}
/**
* #inheritDoc
*/
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
private class ListItr implements ListIterator<E> {
private NodeAndFather next;
private int nextIndex;
private int expectedModCount = modCount;
ListItr(int index) {
assert isPositionIndex(index);
next = node(index);
nextIndex = index;
}
public boolean hasNext() {
final BinaryTreeNode<E> cur = next.node;
return cur != null || (next.father.leftIsNull || next.father.rightIsNull);
}
//O(n)
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
final E result = next.node != null ? next.node.value : null;
next = node(nextIndex+1);
nextIndex++;
return result;
}
public boolean hasPrevious() {
throw new UnsupportedOperationException();
}
public E previous() {
throw new UnsupportedOperationException();
}
public int nextIndex() {
throw new UnsupportedOperationException();
}
public int previousIndex() {
throw new UnsupportedOperationException();
}
public void remove() {
throw new UnsupportedOperationException();
}
public void set(E e) {
throw new UnsupportedOperationException();
}
public void add(E e) { // always append at the tail
checkForComodification();
if (next == null) { // empty list
BinaryTreeNode.this.value = e;
BinaryTreeNode.this.left = null;
BinaryTreeNode.this.right = null;
} else {
final BinaryTreeNode<E> newNode = e != null ? new BinaryTreeNode<>(e) : null;
if (next.father == null) { // root
BinaryTreeNode<E> cur = next.node;
cur.left = newNode;
assert cur.right == null;
throw new UnsupportedOperationException();
} else {
if (next.isRight) {
if (next.father.right != null) throw new IllegalStateException();
next.father.right = newNode;
if (newNode == null) {
next.father.rightIsNull = true;
}
} else {
if (next.father.left != null) throw new IllegalStateException();
next.father.left = newNode;
if (newNode == null) {
next.father.leftIsNull = true;
}
}
}
}
modCount++;
expectedModCount++;
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
// the following functions are just for unit tests.
ArrayList<E> preOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
preOrder(this, result);
return result;
}
private static <E> void preOrder(BinaryTreeNode<E> root, ArrayList<E> result) {
if (root == null)
return;
result.add(root.value);
if (root.left != null)
preOrder(root.left, result);
if (root.right != null)
preOrder(root.right, result);
}
ArrayList<E> inOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
inOrder(this, result);
return result;
}
private static <E> void inOrder(BinaryTreeNode<E> root, ArrayList<E> result) {
if (root == null)
return;
if (root.left != null)
inOrder(root.left, result);
result.add(root.value);
if (root.right != null)
inOrder(root.right, result);
}
ArrayList<E> postOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
postOrder(this, result);
return result;
}
private static <E> void postOrder(BinaryTreeNode<E> root, ArrayList<E> result) {
if (root == null)
return;
if (root.left != null)
postOrder(root.left, result);
if (root.right != null)
postOrder(root.right, result);
result.add(root.value);
}
ArrayList<E> levelOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
Queue<BinaryTreeNode<E>> queue = new LinkedList<>();
queue.add(this);
while (!queue.isEmpty()) {
final BinaryTreeNode<E> node = queue.remove();
result.add(node.value);
if (node.left != null)
queue.add(node.left);
if (node.right != null)
queue.add(node.right);
}
return result;
}
}
Then comes with the unit tests:
java
package me.soulmachine.customized_collection;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class BinaryTreeNodeTest
{
#Test public void deserializeTest() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
final List<Integer> intList = Arrays.asList(2,1,10,null,null,5);
/*
2
/ \
1 10
/
5
*/
// TODO: the time complexity is O(n^2)
final BinaryTreeNode<Integer> intTree = objectMapper.readValue("[2,1,10,null,null,5]",
new TypeReference<BinaryTreeNode<Integer>>() {});
assertEquals(intList, intTree);
assertEquals(Arrays.asList(2, 1, 10, 5), intTree.levelOrder());
assertEquals(Arrays.asList(2, 1, 10, 5), intTree.preOrder());
assertEquals(Arrays.asList(1, 2, 5, 10), intTree.inOrder());
assertEquals(Arrays.asList(1, 5, 10, 2), intTree.postOrder());
}
}
This article is inspired by Tatu Saloranta from this post, special thanks to him!
Here is my original blog, Deserialize a JSON String to a Binary Tree

Defining methods and variables

I am a beginner and I am trying to understand what is static, private, public. Please see the following example written by me. It works, but I have very big doubts whether this is a correct way of defining variables and methods. Thanks in advance!
import java.util.Scanner;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Biorhytm {
private static String nameOne;
private static String nameTwo;
private static String dobOneIn;
private static String dobTwoIn;
private static Date dobOne;
private static Date dobTwo;
static int diff;
public static Date getDobOne() {
return dobOne;
}
public static void setDobOne(Date dobOne) {
Biorhytm.dobOne = dobOne;
}
public static Date getDobTwo() {
return dobTwo;
}
public static void setDobTwo(Date dobTwo) {
Biorhytm.dobTwo = dobTwo;
}
public static String getDobOneIn() {
return dobOneIn;
}
public static void setDobOneIn(String dobOneIn) {
Biorhytm.dobOneIn = dobOneIn;
}
public static String getDobTwoIn() {
return dobTwoIn;
}
public static void setDobTwoIn(String dobTwoIn) {
Biorhytm.dobTwoIn = dobTwoIn;
}
public static String getNameOne() {
return nameOne;
}
public static void setNameOne(String nameOne) {
Biorhytm.nameOne = nameOne;
}
public static String getNameTwo() {
return nameTwo;
}
public static void setNameTwo(String nameTwo) {
Biorhytm.nameTwo = nameTwo;
}
public static int diffCalc() {
return diff = Math.abs((int)((getDobOne().getTime() - getDobTwo().getTime()) / (24 * 60 * 60 * 1000)));
}
public static void main(String[] args) {
float physicalBio;
float emotionalBio;
float intellectualBio;
boolean validEntry;
Scanner input = new Scanner(System.in);
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
SimpleDateFormat format2 = new SimpleDateFormat("EEEE, MMMM d, yyyy", java.util.Locale.US);
System.out.println("Enter name of first person!");
setNameOne(input.nextLine());
if (getNameOne().equals("")) {
setNameOne("first person");
}
System.out.println("Enter name of second person!");
setNameTwo(input.nextLine());
if (getNameTwo().equals("")) {
setNameTwo("second person");
}
do {
try {
System.out.println("Enter date of birth of " + getNameOne() + "! (MM/DD/YYYY)");
setDobOneIn(input.nextLine());
setDobOne(format.parse(getDobOneIn()));
validEntry = true;
}
catch (ParseException e) {
validEntry = false;
}
} while (!validEntry);
do {
try {
System.out.println("Enter date of birth of " + getNameTwo() + "! (MM/DD/YYYY)");
setDobTwoIn(input.nextLine());
setDobTwo(format.parse(getDobTwoIn()));
validEntry = true;
}
catch (ParseException e) {
validEntry = false;
}
} while (!validEntry);
System.out.println();
System.out.println("DOB of " + getNameOne() + ": " + format2.format(getDobOne()) + ".");
System.out.println("DOB of " + getNameTwo() + ": " + format2.format(getDobTwo()) + ".");
System.out.println("Difference between DOBs (days): " + diffCalc() + ".");
physicalBio = diffCalc() % 23;
emotionalBio = diffCalc() % 28;
intellectualBio = diffCalc() % 33;
physicalBio /= 23;
emotionalBio /= 28;
intellectualBio /= 33;
if (physicalBio > 0.5) {
physicalBio = 1 - physicalBio;
}
if (emotionalBio > 0.5) {
emotionalBio = 1 - emotionalBio;
}
if (intellectualBio > 0.5) {
intellectualBio = 1 - intellectualBio;
}
physicalBio = 100 - (physicalBio * 100);
emotionalBio = 100 - (emotionalBio * 100);
intellectualBio = 100 - (intellectualBio * 100);
System.out.println("Physical compatibility: " + java.lang.Math.round(physicalBio) + " %.");
System.out.println("Emotional compatibility: " + java.lang.Math.round(emotionalBio) + " %.");
System.out.println("Intellectual compatibility: " + java.lang.Math.round(intellectualBio) + " %.");
}
}
You'd rather have your Biorhythm class be something representing the data about a single person. So you'd create two instances of it (call them "one" and "two", say) and make them non-static. It would have instance variables, not static variables, representing name and date of birth.
class Biorhythm {
private Date dob;
private String name;
Biorhythm(String name, Date dob) {
this.name = name;
this.dob = dob;
}
public String getName() {
return name;
}
public Date getDob() {
return dob;
}
}
public static void main(String[] args) {
Date onedob = /* implementation omitted */
Biorhythm one = new Biorhythm("maxval", onedob);
System.out.println("one: name=" + one.getName() + " date=" + one.getDob());
/* and so forth */
}
You don't really have a need for setXXX() methods because these values aren't probably going to change in your program.
Now create two instances of this class in your main() method. I'll leave the implementation of the calculation methods as an exercise for the time being, since there would be several decent designs for implementing them (in terms of the object-oriented question you asked).
First let me explain what these keywords are-
private,default,protected.public are ACCESS SPECIFIERS.
public-as the word says ,can be accessed everywhere and all members can be public.
protected-can be accessed outside the package in case of inheritance.
default-access able within the package and all members can be default.
private-scope lies within the class,cant be inherited.
And remember these can be used with variables,methods,even classes.
static-can be used when there is no need to invoke methods or access variables with objects.
static members doesn't belong to object and initialised at the time of loading a class.
for ex:
class Converter{
public static long convert(long val){
return val;
}
class User{
long value=Converter.convert(500);//calling convert with class name}

KeyTyped being called twice in this code?

There is a bug somewhere here. For some reason, when I am sending the message to the server, every message is received twice for any single keystroke! for instance, i type "a", and the server receives "INSERT 0 1 a" "INSERT 0 1 a". I'm not sure why it happens twice do you know?
package client;
import javax.swing.*;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.*;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class JTextAreaListen extends JFrame implements KeyListener,
CaretListener {
private static final long serialVersionUID = 6950001634065526391L;
private JTextArea textArea;
protected final PrintWriter out;
protected final int id;
protected final BufferedReader in;
protected static int caretPos;
private static int cMark;
protected static boolean text_selected;
/*
* Connecting to server. (1337 is the port we are going to use).
*
* socket = new Socket(InetAddress.getByName("127.0.0.1"), 1337);
*
* (Open a new outStream, you can save this instead of opening on every time
* you want to send a message. If the connection is lost your should to
* out.close();
*
* out = new PrintWriter(socket.getOutputStream(), true);
*
* out.print("message"); to send something to the server.
*/
public JTextAreaListen(PrintWriter out, BufferedReader in, int id) {
super("JTextAreaListen");
this.id = id;
this.out = out;
this.in = in;
TextEditor.document.addCaretListener(this);
TextEditor.document.addKeyListener(this);
}
// Listener methods
public void changedUpdate(DocumentEvent ev) {
}
public void removeUpdate(DocumentEvent ev) {
}
public void insertUpdate(DocumentEvent ev) {
}
#Override
public void keyPressed(KeyEvent arg0) {
System.out.print("KeyPressedd");
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent ev) {
System.out.println(ev.KEY_PRESSED);
System.out.println("Sth happening!");
System.out.println(ev.getKeyCode());
int evID = ev.getID();
String keyString;
int keyCode;
if (evID == KeyEvent.KEY_TYPED) {
if (ev.getKeyChar() == KeyEvent.CHAR_UNDEFINED) {
keyCode = ev.getKeyCode();
if (keyCode == 8) {
if (text_selected) {
if (caretPos > cMark) {
for (int i = caretPos; i >= cMark; i--) {
System.out.println("sm1");
sendMessage("DELETE" + " " + String.valueOf(id)
+ " " + String.valueOf(cMark + 1));
}
} else if (caretPos < cMark) {
for (int i = caretPos; i >= cMark; i++) {
System.out.println("sm2");
sendMessage("DELETE" + " " + String.valueOf(id)
+ " " + String.valueOf(cMark + 1));
}
}
} else {
System.out.println("sm3");
sendMessage("DELETE" + " " + String.valueOf(id) + " "
+ String.valueOf(caretPos + 1));
}
}
} else {
char c = ev.getKeyChar();
boolean capital = ev.isShiftDown();
String charString = String.valueOf(c);
if (capital) {
charString.toUpperCase();
}
if (text_selected) {
if (caretPos > cMark) {
for (int i = caretPos; i >= cMark; i--) {
System.out.println("sm4");
sendMessage("DELETE" + " " + String.valueOf(id)
+ " " + String.valueOf(cMark + 1));
}
System.out.println("sm5");
sendMessage("INSERT" + " " + String.valueOf(id) + " "
+ String.valueOf(cMark) + " " + charString);
} else if (caretPos < cMark) {
for (int i = caretPos; i >= cMark; i++) {
System.out.println("sm6");
sendMessage("DELETE" + " " + String.valueOf(id)
+ " " + String.valueOf(caretPos + 1));
}
System.out.println("sm7");
sendMessage("INSERT" + " " + String.valueOf(id) + " "
+ String.valueOf(caretPos) + " " + charString);
}
} else {
System.out.println("sm8");
sendMessage("INSERT" + " " + String.valueOf(id) + " "
+ String.valueOf(caretPos) + " " + charString);
}
}
}
}
public void sendMessage(String s) {
System.out.println("smReal");
out.println(s);
}
#Override
public void caretUpdate(CaretEvent cev) {
int dot = cev.getDot();
int mark = cev.getMark();
caretPos = dot;
cMark = mark;
if (dot == mark) {
text_selected = false;
} else if ((dot < mark) | (dot > mark)) {
text_selected = true;
}
}
}
Here is the code for the client containing the TextArea which calls this Listener.
package client;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.text.DefaultEditorKit;
public class TextEditor extends JFrame {
private static final long serialVersionUID = 5991470239888613993L;
protected static JTextArea document = new JTextArea(20, 120);
private JFileChooser dialog = new JFileChooser(
System.getProperty("user.dir"));
private String currentFile = "Untitled";
private boolean changed = false;
private int id;
private final BufferedReader in;
private final PrintWriter out;
public TextEditor(final PrintWriter out, final BufferedReader in, int id) {
this.out = out;
this.in = in;
this.id = id;
document.setFont(new Font("Monospaced", Font.PLAIN, 12));
JScrollPane scroll = new JScrollPane(document,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
this.add(scroll, BorderLayout.CENTER);
JMenuBar JMB = new JMenuBar();
this.setJMenuBar(JMB);
JMenu file = new JMenu("File");
JMenu edit = new JMenu("Edit");
JMB.add(file);
JMB.add(edit);
file.add(Open);
file.add(Save);
file.add(Quit);
file.add(SaveAs);
file.addSeparator();
for (int i = 0; i < 4; i++)
file.getItem(i).setIcon(null);
edit.add("Cut");
edit.add("Copy");
edit.add("Paste");
edit.getItem(0).setText("Cut");
edit.getItem(1).setText("Copy");
edit.getItem(2).setText("Paste");
JToolBar tool = new JToolBar();
this.add(tool, BorderLayout.NORTH);
tool.add(Open);
tool.add(Save);
tool.addSeparator();
JButton cut = tool.add(Cut), copy = tool.add(Copy), paste = tool
.add(Paste);
cut.setText(null);
cut.setIcon(new ImageIcon("cut.png"));
copy.setText(null);
copy.setIcon(new ImageIcon("copy.png"));
paste.setText(null);
paste.setIcon(new ImageIcon("paste.png"));
Save.setEnabled(false);
SaveAs.setEnabled(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
document.addKeyListener(new JTextAreaListen(out, in, id));
setTitle(currentFile);
setVisible(true);
final int id2 = id;
Thread t = new Thread(new Runnable() {
public void run() {
out.println("GET " + id2);
while (true) {
out.println("GET " + id2);
String line = null;
do {
try {
line = in.readLine();
} catch (IOException e) {
JOptionPane.showMessageDialog(null,
"Connection Lost", "Error",
JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
} while (line == null);
int temp = JTextAreaListen.caretPos;
document.setText(line);
document.setCaretPosition(temp);
}
}
});
t.start();
}
private KeyListener keyPressed = new KeyAdapter() {
public void keyPressed(KeyEvent e) {
changed = true;
Save.setEnabled(true);
SaveAs.setEnabled(true);
}
};
Action Open = new AbstractAction("Open", new ImageIcon("open.png")) {
private static final long serialVersionUID = -474289105133169886L;
public void actionPerformed(ActionEvent e) {
saveOld();
if (dialog.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
readInFile(dialog.getSelectedFile().getAbsolutePath());
}
SaveAs.setEnabled(true);
}
};
Action Save = new AbstractAction("Save", new ImageIcon("save.png")) {
private static final long serialVersionUID = 2064233284536910855L;
public void actionPerformed(ActionEvent e) {
if (!currentFile.equals("Untitled"))
saveFile(currentFile);
else
saveFileAs();
}
};
Action SaveAs = new AbstractAction("Save as...") {
private static final long serialVersionUID = -5473532525926088880L;
public void actionPerformed(ActionEvent e) {
saveFileAs();
}
};
Action Quit = new AbstractAction("Quit") {
private static final long serialVersionUID = -5339245808869817726L;
public void actionPerformed(ActionEvent e) {
saveOld();
System.exit(0);
}
};
ActionMap m = document.getActionMap();
Action Cut = m.get(DefaultEditorKit.cutAction);
Action Copy = m.get(DefaultEditorKit.copyAction);
Action Paste = m.get(DefaultEditorKit.pasteAction);
private void saveFileAs() {
if (dialog.showSaveDialog(null) == JFileChooser.APPROVE_OPTION)
saveFile(dialog.getSelectedFile().getAbsolutePath());
}
private void saveOld() {
if (changed) {
if (JOptionPane.showConfirmDialog(this, "Save " + currentFile
+ " ?", "Save", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
saveFile(currentFile);
}
}
private void readInFile(String fileName) {
try {
FileReader r = new FileReader(fileName);
document.read(r, null);
r.close();
currentFile = fileName;
setTitle(currentFile);
changed = false;
} catch (IOException e) {
Toolkit.getDefaultToolkit().beep();
JOptionPane.showMessageDialog(this, "Could not find " + fileName);
}
}
private void saveFile(String fileName) {
try {
FileWriter w = new FileWriter(fileName);
document.write(w);
w.close();
currentFile = fileName;
setTitle(currentFile);
changed = false;
Save.setEnabled(false);
} catch (IOException e) {
JOptionPane
.showMessageDialog(this,
"An error has occurred. Your document may not have been saved");
}
}
}

Exporting a non public Type through public API

I am trying to follow Trees tutorial at: http://cslibrary.stanford.edu/110/BinaryTrees.html
Here is the code I have written so far:
package trees.bst;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
*
* #author sachin
*/
public class BinarySearchTree {
Node root = null;
class Node {
Node left = null;
Node right = null;
int data = 0;
public Node(int data) {
this.left = null;
this.right = null;
this.data = data;
}
}
public void insert(int data) {
root = insert(data, root);
}
public boolean lookup(int data) {
return lookup(data, root);
}
public void buildTree(int numNodes) {
for (int i = 0; i < numNodes; i++) {
int num = (int) (Math.random() * 10);
System.out.println("Inserting number:" + num);
insert(num);
}
}
public int size() {
return size(root);
}
public int maxDepth() {
return maxDepth(root);
}
public int minValue() {
return minValue(root);
}
public int maxValue() {
return maxValue(root);
}
public void printTree() { //inorder traversal
System.out.println("inorder traversal:");
printTree(root);
System.out.println("\n--------------");
}
public void printPostorder() { //inorder traversal
System.out.println("printPostorder traversal:");
printPostorder(root);
System.out.println("\n--------------");
}
public int buildTreeFromOutputString(String op) {
root = null;
int i = 0;
StringTokenizer st = new StringTokenizer(op);
while (st.hasMoreTokens()) {
String stNum = st.nextToken();
int num = Integer.parseInt(stNum);
System.out.println("buildTreeFromOutputString: Inserting number:" + num);
insert(num);
i++;
}
return i;
}
public boolean hasPathSum(int pathsum) {
return hasPathSum(pathsum, root);
}
public void mirror() {
mirror(root);
}
public void doubleTree() {
doubleTree(root);
}
public boolean sameTree(BinarySearchTree bst) { //is this tree same as another given tree?
return sameTree(this.root, bst.getRoot());
}
public void printPaths() {
if (root == null) {
System.out.println("print path sum: tree is empty");
}
List pathSoFar = new ArrayList();
printPaths(root, pathSoFar);
}
///-------------------------------------------Public helper functions
public Node getRoot() {
return root;
}
//Exporting a non public Type through public API
///-------------------------------------------Helper Functions
private boolean isLeaf(Node node) {
if (node == null) {
return false;
}
if (node.left == null && node.right == null) {
return true;
}
return false;
}
///-----------------------------------------------------------
private boolean sameTree(Node n1, Node n2) {
if ((n1 == null && n2 == null)) {
return true;
} else {
if ((n1 == null || n2 == null)) {
return false;
} else {
if ((n1.data == n2.data)) {
return (sameTree(n1.left, n2.left) && sameTree(n1.right, n2.right));
}
}
}
return false;
}
private void doubleTree(Node node) {
//create a copy
//bypass the copy to continue looping
if (node == null) {
return;
}
Node copyNode = new Node(node.data);
Node temp = node.left;
node.left = copyNode;
copyNode.left = temp;
doubleTree(copyNode.left);
doubleTree(node.right);
}
private void mirror(Node node) {
if (node == null) {
return;
}
Node temp = node.left;
node.left = node.right;
node.right = temp;
mirror(node.left);
mirror(node.right);
}
private void printPaths(Node node, List pathSoFar) {
if (node == null) {
return;
}
pathSoFar.add(node.data);
if (isLeaf(node)) {
System.out.println("path in tree:" + pathSoFar);
pathSoFar.remove(pathSoFar.lastIndexOf(node.data)); //only the current node, a node.data may be duplicated
return;
} else {
printPaths(node.left, pathSoFar);
printPaths(node.right, pathSoFar);
}
}
private boolean hasPathSum(int pathsum, Node node) {
if (node == null) {
return false;
}
int val = pathsum - node.data;
boolean ret = false;
if (val == 0 && isLeaf(node)) {
ret = true;
} else if (val == 0 && !isLeaf(node)) {
ret = false;
} else if (val != 0 && isLeaf(node)) {
ret = false;
} else if (val != 0 && !isLeaf(node)) {
//recurse further
ret = hasPathSum(val, node.left) || hasPathSum(val, node.right);
}
return ret;
}
private void printPostorder(Node node) { //inorder traversal
if (node == null) {
return;
}
printPostorder(node.left);
printPostorder(node.right);
System.out.print(" " + node.data);
}
private void printTree(Node node) { //inorder traversal
if (node == null) {
return;
}
printTree(node.left);
System.out.print(" " + node.data);
printTree(node.right);
}
private int minValue(Node node) {
if (node == null) {
//error case: this is not supported
return -1;
}
if (node.left == null) {
return node.data;
} else {
return minValue(node.left);
}
}
private int maxValue(Node node) {
if (node == null) {
//error case: this is not supported
return -1;
}
if (node.right == null) {
return node.data;
} else {
return maxValue(node.right);
}
}
private int maxDepth(Node node) {
if (node == null || (node.left == null && node.right == null)) {
return 0;
}
int ldepth = 1 + maxDepth(node.left);
int rdepth = 1 + maxDepth(node.right);
if (ldepth > rdepth) {
return ldepth;
} else {
return rdepth;
}
}
private int size(Node node) {
if (node == null) {
return 0;
}
return 1 + size(node.left) + size(node.right);
}
private Node insert(int data, Node node) {
if (node == null) {
node = new Node(data);
} else if (data <= node.data) {
node.left = insert(data, node.left);
} else {
node.right = insert(data, node.right);
}
//control should never reach here;
return node;
}
private boolean lookup(int data, Node node) {
if (node == null) {
return false;
}
if (node.data == data) {
return true;
}
if (data < node.data) {
return lookup(data, node.left);
} else {
return lookup(data, node.right);
}
}
public static void main(String[] args) {
BinarySearchTree bst = new BinarySearchTree();
int treesize = 5;
bst.buildTree(treesize);
//treesize = bst.buildTreeFromOutputString("4 4 4 6 7");
treesize = bst.buildTreeFromOutputString("3 4 6 3 6");
//treesize = bst.buildTreeFromOutputString("10");
for (int i = 0; i < treesize; i++) {
System.out.println("Searching:" + i + " found:" + bst.lookup(i));
}
System.out.println("tree size:" + bst.size());
System.out.println("maxDepth :" + bst.maxDepth());
System.out.println("minvalue :" + bst.minValue());
System.out.println("maxvalue :" + bst.maxValue());
bst.printTree();
bst.printPostorder();
int pathSum = 10;
System.out.println("hasPathSum " + pathSum + ":" + bst.hasPathSum(pathSum));
pathSum = 6;
System.out.println("hasPathSum " + pathSum + ":" + bst.hasPathSum(pathSum));
pathSum = 19;
System.out.println("hasPathSum " + pathSum + ":" + bst.hasPathSum(pathSum));
bst.printPaths();
bst.printTree();
//bst.mirror();
System.out.println("Tree after mirror function:");
bst.printTree();
//bst.doubleTree();
System.out.println("Tree after double function:");
bst.printTree();
System.out.println("tree size:" + bst.size());
System.out.println("Same tree:" + bst.sameTree(bst));
BinarySearchTree bst2 = new BinarySearchTree();
bst2.buildTree(treesize);
treesize = bst2.buildTreeFromOutputString("3 4 6 3 6");
bst2.printTree();
System.out.println("Same tree:" + bst.sameTree(bst2));
System.out.println("---");
}
}
Now the problem is that netbeans shows Warning: Exporting a non public Type through public API for function getRoot().
I write this function to get root of tree to be used in sameTree() function, to help comparison of "this" with given tree.
Perhaps this is a OOP design issue... How should I restructure the above code that I do not get this warning and what is the concept I am missing here?
The issue here is that some code might call getRoot() but won't be able to use it's return value since you only gave package access to the Node class.
Make Node a top level class with its own file, or at least make it public
I don't really understand why you even created the getRoot() method. As long as you are inside your class you can even access private fields from any other object of the same class.
So you can change
public boolean sameTree(BinarySearchTree bst) { //is this tree same as another given tree?
return sameTree(this.root, bst.getRoot());
}
to
public boolean sameTree(BinarySearchTree bst) { //is this tree same as another given tree?
return sameTree(this.root, bst.root);
}
I would also add a "short path" for the case you pass the same instance to this method:
public boolean sameTree(BinarySearchTree bst) { //is this tree same as another given tree?
if (this == bst) {
return true;
}
return sameTree(this.root, bst.root);
}