So I have this code:
public class RemoteImpl extends UnicastRemoteObject implements TestRemote {
private static final long serialVersionUID = 1L;
private static int counter = 0;
private int localizedCounter = 0;
protected RemoteImpl() throws RemoteException {
super();
}
#Override
public int getMeGlobalCounter() throws RemoteException {
counter++;
return counter;
}
#Override
public int getMeLocalizedCounter() throws RemoteException {
localizedCounter++;
return localizedCounter;
}
}
And with my Client I am trying:
public class TestClient {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.getRegistry("localhost", Constant.RMI_PORT);
TestRemote remote = (TestRemote) registry.lookup(Constant.RMI_ID);
System.out.println("Global counter:" + remote.getMeGlobalCounter());
System.out.println("Localized counter:" + remote.getMeLocalizedCounter());
}
}
After running this code for the 2 times I am expecting to see:
Global counter:3
Localized counter:1
however I see that
Localized counter:3
So why is the localized counter not reset everytime I invoke this method? Am I not getting a new object everytime?
Am I not getting a new object every time?
No you aren't. You're getting the same instance that was bound into the Registry. RMI doesn't just create remote objects willy-nilly.
Related
I am using Hystrix to improve my services. How can I decapsulate the service calls into Hystrix. I know you can create for each call a special hystrix-class, but this would be too much work without using Spring!
I try to describe my problem with pseudocode:
public class HystrixController extends HystrixCommand {
public static void main(String[] args) throws Exception {
HystrixController hystrixController = new HystrixController();
System.out.print(hystrixController.execute());
}
private final ExampleService exampleService;
protected HystrixController() throws Exception {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.exampleService = new ExampleService();
}
// Call 1
public List getItemsAsList() {
return exampleService.getItemsByContractId(contractID);
}
// Call 2
public List getItemsByName() {
return exampleService.getItemsByName(contractID);
}
// How can I isolate the two calls ? The run() only allows me to use one.
#Override
protected List run() throws Exception {
return getItemsAsList();
}
}
In the example you can see it is only possible to execute only one call. I would like to have something like that:
public class HystrixController extends HystrixCommand {
public static void main(String[] args) throws Exception {
HystrixController hystrixController = new HystrixController();
System.out.print(hystrixController.execute(1));
System.out.print(hystrixController.execute(2));
}
private final ExampleService exampleService;
protected HystrixController() throws Exception {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.exampleService = new ExampleService();
}
// Call 1
public List getItemsAsList() {
return exampleService.getItemsByContractId(contractID);
}
// Call 2
public List getItemsByName() {
return exampleService.getItemsByName(contractID);
}
// Multi Threads
#Override
protected List run_getItemsAsList() throws Exception {
return getItemsAsList();
}
#Override
protected List run_getItemsByName() throws Exception {
return getItemsByName();
}
}
Thanks you in advance and I am sorry for my broken English
I'm trying to call getSetting() from SettingsItem.java in SingleChoiceViewHolder.java. Is there a way to call getSetting() while keeping SettingsItem a non-static abstract class? Here's what I tried to add to SingleChoiceViewHolder.java, however Android Studio says that 'SettingsItem' is abstract; cannot be instantiated.:
SettingsItem instance = new SettingsItem();
instance.getSetting();
IntSetting setting = (IntSetting) getSetting();
mTextSettingDescription.setText(setting.getValue());
I also tried I tried converting SettingsItem to an interface and implementing it alongside SingleChoiceViewHolder extends SettingViewHolder but the original problem still remained.
The files are attached below.
SingleChoiceViewHolder.java:
public final class SingleChoiceViewHolder extends SettingViewHolder
{
private SingleChoiceSetting mItem;
private TextView mTextSettingName;
private TextView mTextSettingDescription;
public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView, adapter);
}
#Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
}
#Override
public void bind(SettingsItem item)
{
mItem = (SingleChoiceSetting) item;
mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() == R.string.dynamic_descriptionId)
{
SettingsItem instance = new SettingsItem();
instance.getSetting();
IntSetting setting = (IntSetting) getSetting();
mTextSettingDescription.setText(setting.getValue());
}
if (item.getDescriptionId() > 0 && item.getDescriptionId() != R.string.dynamic_descriptionId)
{
mTextSettingDescription.setText(item.getDescriptionId());
}
}
#Override
public void onClick(View clicked)
{
getAdapter().onSingleChoiceClick(mItem);
}
SettingsItem.java:
public abstract class SettingsItem
{
public static final int TYPE_HEADER = 0;
public static final int TYPE_CHECKBOX = 1;
public static final int TYPE_SINGLE_CHOICE = 2;
public static final int TYPE_SLIDER = 3;
public static final int TYPE_SUBMENU = 4;
public static final int TYPE_INPUT_BINDING = 5;
public static final int TYPE_RADIO_BUTTON = 6;
private String mKey;
private String mSection;
private int mFile;
private Setting mSetting;
private int mNameId;
private int mDescriptionId;
public SettingsItem(String key, String section, int file, Setting setting, int nameId, int descriptionId)
{
mKey = key;
mSection = section;
mFile = file;
mSetting = setting;
mNameId = nameId;
mDescriptionId = descriptionId;
}
public String getKey()
{
return mKey;
}
public String getSection()
{
return mSection;
}
public int getFile()
{
return mFile;
}
public Setting getSetting()
{
return mSetting;
}
public void setSetting(Setting setting)
{
mSetting = setting;
}
public int getNameId()
{
return mNameId;
}
public int getDescriptionId()
{
return mDescriptionId;
}
public abstract int getType();
}
Since getSetting() is not a static method, you need to invoke it on an instance of some concrete class that extends the abstract class SettingsItem.
Think about it. If you have two instances of such a class, and the mSetting variable is different for the two instances, which one should be returned from a static-like call to getSetting()?
By definition abstract class means it is not instantiated but you can inherit from it. If you want to create many different objects with the same values but different names you can just extend SettingsItem.
Also, if you want more abstraction for future use you can create an interface with the same methods as the abstract methods in case you need to make customize methods for a different settings item.
Example:
interface SettingsInterface {
void doSomething();
}
class abstract SettingsItem implements SettingsInterface {
public void doSomething() {
System.out.println("Hello");
}
}
class RegularSettings extends SettingsItem {}
class CustomSettings implements SettingsInterface {
public void doSomething() {
System.out.println("Goodbye");
}
}
class TestClass {
public static void testAbstract(SettingsItem extendedAbstract) {
extendedAbstract.doSomething();
}
public static void testInterface(SettingsInterface interface) {
interface.doSomething();
}
public static void main(String[] args) {
SettingsItem abstractExtended = new RegularSettings();
// also could be CustomSettings instead of SettingsInterface
SettingsInterface customClass = new CustomSettings();
testInterface(abstractExtended);
testInterface(customClass);
testAbstract(abstractExtended);
// will throw errors since it doesn't extend SettingsItem
testAbstract(customClass);
}
}
My aim is to make a simple chat program. I'm new at RMI. What I've got so far is that the server works. I start it. Then I start the client, it transfers the strings to the server through RMI. But then it doesn't appear on the GUI I made. That's where my problem lies.
My project structure
My StartClient class. I created a chatClient, and put the chatServer stub as parameter.
public StartClient() throws RemoteException, NotBoundException, MalformedURLException {
chatServer = (ChatServer) Naming.lookup("rmi://localhost:1099/chatServer");
}
private void run() throws RemoteException, MalformedURLException, NotBoundException {
ChatClientImpl chatClient1 = new ChatClientImpl(chatServer, "ikke");
new ChatFrame(chatClient1);
ChatClientImpl chatClient2 = new ChatClientImpl(chatServer, "bla");
new ChatFrame(chatClient2);
}
public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {
StartClient start = new StartClient();
start.run();
}
In the ChatClientImpl constructor I use the remote method register.
public ChatClientImpl(ChatServer chatServer, String name) throws MalformedURLException, NotBoundException, RemoteException {
this.chatServer = chatServer;
this.name = name;
chatServer.register(this);
}
Now we're in the ChatServerImpl class, in the REGISTER method. I add the client to an ArrayList of clients. Then I use the method SENT to display the text. It calls the RECEIVE method that each client object has.
public class ChatServerImpl extends UnicastRemoteObject implements ChatServer {
private List<ChatClient> clients;
public ChatServerImpl() throws RemoteException {
this.clients = new ArrayList<ChatClient>();
}
public void register(ChatClientImpl client) throws RemoteException {
clients.add(client);
send("server", client.getName() + " has entered the room");
}
public void unregister(ChatClientImpl client) throws RemoteException {
clients.remove(client);
send("server", client.getName() + " has left the room");
}
public void send(String name, String message) throws RemoteException {
for(ChatClient client : clients) {
client.receive(name + ": " + message);
}
}
}
This is where things go wrong. The textReceiver is ALWAYS null. (textReceiver is attribute/field of the client object.)
public void receive(String message) {
if (textReceiver == null) return;
textReceiver.receive(message);
}
The ArrayList of clients are server-side and all the clients in there all have their textReceivers set on null. If you look back at StartClient there's an important line. The new ChatFrame(chatClient). In the ChatFrame's constructor is where I set the textReceiver.
public ChatFrame(ChatClientImpl chatClient) {
this.chatClient = chatClient;
chatClient.setTextReceiver(this);
String name = chatClient.getName();
setTitle("Chat: " + name);
createComponents(name);
layoutComponents();
addListeners();
setSize(300, 300);
setVisible(true);
}
This project works when I don't use RMI and they're in one package but once I separate them into client-server this problem arose. How do I communicate between them? Server-side I have an (irrelevant?) list of ChatClients that don't influence anything even though the text arrives.
Do I use RMI for every separate ChatClient and make the ChatServer connect with it and send the text like that? Seems very complicated to me. How do I go about this?
EDIT:
ChatClientImpl class
public class ChatClientImpl implements ChatClient, Serializable {
private ChatServer chatServer;
private TextReceiver textReceiver;
private String name;
public ChatClientImpl(ChatServer chatServer, String name) throws MalformedURLException, NotBoundException, RemoteException {
this.chatServer = chatServer;
this.name = name;
chatServer.register(this);
}
public String getName() {
return name;
}
public void send(String message) throws RemoteException {
chatServer.send(name, message);
}
public void receive(String message) {
if (textReceiver == null) return;
textReceiver.receive(message);
}
public void setTextReceiver(TextReceiver textReceiver) {
this.textReceiver = textReceiver;
}
public void unregister() throws RemoteException {
chatServer.unregister(this);
}
}
Your ChatClientImpl class isn't an exported remote object, so it will be serialized to the server, and execute there. And because register() happens during construction, it will be serialized before the setReceiverTextReceiver() method is called. So, the corresponding field will be null. At the server. This is not what you want and it is also not where you want it.
So, make it extend UnicastRemoteObject and implement your ChatClient (presumed) remote interface. If you have problems with doing that, solve them. Don't just mess around with things arbitrarily. And it should not implement Serializable.
NB The signature of register() should be register(ChatClient client). Nothing to do with the ChatClientImpl class. Ditto for unregister().
public class keyClientHandler extends ChannelInboundHandlerAdapter{
public static ConcurrentHashMap<String, String> keyTable = new ConcurrentHashMap<>();
String information;
String hashMapKey;
String hashMapValue;
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// do something
keyTable.put(hashMapKey, hashMapValue);
System.out.println(keyTable.size()); //size = 268
}
public static ConcurrentHashMap<String,String> getKeyTable() {
return keyTable;
}
Another class use:
public static void main(String[] args) {
ConcurrentHashMap<String, String> map = keyClientHandler.getKeyTable();
System.out.println(map.size()); //size=0
}
When i try to use stuffed concurrentMap on another class or in the main method, it returns empty.
How can i use Concurentmap from another classes?
How we interpreted your problem?
public static ConcurrentHashMap<String, String> keyTable = new ConcurrentHashMap<>();
static concurrentHashMap has been defined in class KeyClientHandler. You intended to retrieve the map object and print the size of the map from main method of another class. Now as you said, your program runs and it prints 0 as the output. This means you are alright in terms of accessing the map. You should have got compilation errors, if your concurrentHashMap was not accessible from the said main method of another class.
What can be a possible way to demonstrate that this better?
I think the following improvements are required. Firstly, you don't need to use static map or static methods here. We can demonstrate this without static'ness as well. Try running this example which is a slight modification of your code.
import java.util.concurrent.ConcurrentHashMap;
class ChannelHandlerContext {
// some class
}
class KeyClientHandler{
public ConcurrentHashMap<String, String> keyTable = new ConcurrentHashMap<>();
String information;
String hashMapKey;
String hashMapValue;
KeyClientHandler() {
}
public void setKeyValue(String key, String value){
hashMapKey = key;
hashMapValue = value;
}
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// do something
keyTable.put(hashMapKey, hashMapValue);
System.out.println(keyTable.size()); //size = 268
}
public ConcurrentHashMap<String,String> getKeyTable() {
return keyTable;
}
}
public class TestConcurrentHashMap {
public static void main(String[] args) {
KeyClientHandler keyClientHandler = new KeyClientHandler();
keyClientHandler.setKeyValue("apples", "fruit");
ConcurrentHashMap<String, String> map = keyClientHandler.getKeyTable();
try {
keyClientHandler.channelRead(null, null); // not the best thing
System.out.println(map.size()); //size=1
} catch (Exception e) {
e.printStackTrace();
}
}
}
Output:
1
My project is socket programming. I use Netty Framework. I send TCP client and received message send other client.
Server :
public class KeyClient {
static final String HOST = System.getProperty("host", "...");
static final int PORT = Integer.parseInt(System.getProperty("port", "..."));
public static void keyClientStart() throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new keyClientInitializer());
ChannelFuture future = bootstrap.connect(HOST, PORT).sync();
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
KeyClientInitializer :
public class keyClientInitializer extends ChannelInitializer<SocketChannel> {
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LoggingHandler(LogLevel.INFO));
pipeline.addLast(new FixedLengthFrameDecoder(32));
pipeline.addLast(new keyClientHandler());
}
}
KeyClientHandler :
public class keyClientHandler extends ChannelInboundHandlerAdapter{
public static ConcurrentHashMap<String, String> keyTable = new ConcurrentHashMap<>();
String information;
String hashMapKey;
String hashMapValue;
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buffer = (ByteBuf) msg;
byte[] receivedKey = byteBufToByteArray(buffer);
information = DatatypeConverter.printHexBinary(receivedKey);
// do something
// ...
keyTable.put(hashMapKey, hashMapValue); //map has elements
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
public static ConcurrentHashMap<String,String> getKeyTable() {
return keyTable;
}
private byte[] byteBufToByteArray(ByteBuf buffer) {
byte[] receivedKey;
int offset;
int length = buffer.readableBytes();
if (buffer.hasArray()) {
receivedKey = buffer.array();
offset = buffer.arrayOffset();
} else {
receivedKey = new byte[length];
buffer.getBytes(buffer.readerIndex(), receivedKey);
offset = 0;
}
return receivedKey;
}
}
Test class:
public class AppMain {
public static void main(String[] args) throws InterruptedException {
KeyClient.keyClientStart();
ConcurrentHashMap<String, String> map = keyClientHandler.getKeyTable(); // is empty
}
When i add 'System.out.println(keyTable);' in keyClientHandler, i see map values.
Output
On my case it's OK to hold the CHM object on other class, you can check:
Is the System.out.println(keyTable.size()); called after channelRead(...) ? you print the key on which class? if the next channel handler, should you call ctx.fireChannelRead(msg); ?
Other way you can print the CHM hashCode(), if they are the same, that means same object.
I'm struggling understanding how work with java objects from other objects. I have 3 simple classes:
1) environment object
public class Environment {
protected String envName;
public Environment(String envName){
this.envName = envName;
}
// get and set methods
public String getenvName(){
return envName;
}
public void setenvName(String envName){
this.envName = envName;
}
}
2) Class that will populate this object
public class FetchConfig {
Environment environment;
public FetchConfig() {
}
public void buildConfig() {
environment.setenvName("Steve");
}
}
3) A class with main method with will work with my Environment objects:
public class WorkWithEnvironment {
private FetchConfig config;
public static void main(String[] args) throws FileNotFoundException,
IOException {
WorkWithEnvironment w = new WorkWithEnvironment();
w.setupConfig();
w.readEnvNames();
}
private void setupConfig() throws FileNotFoundException, IOException {
config = new FetchConfig();
config.buildConfig();
}
private void readEnvNames() {
System.out.println("Environment name is: "
+ config.environment.getenvName());
}
}
But when I run it, I keep getting an NPE(NullPointerException) here -> environment.setenvName("Steve");
You've never told FetchConfig which Environment to use. I think you meant to have environment = new Environment(); or similar in FetchConfig's default constructor.
You could also initialize the variable environment with a similar line in the buildConfig method.
Your second class is trying to set values inside your Environment Class before instantiating it and so it is null when you try to assign a value to it.
public class FetchConfig {
Environment environment;
public FetchConfig() {
environment = new Environment(null);
}
public void buildConfig() {
environment.setenvName("Steve");
}