Site Search :
Standard Enterprise XML Methodology Pattern Setting Tunning Other
Article Contributors
GuestBook
Javapattern Maven
XSourceGen Dev
JetSpeed Test
JLook Image
jLook Family Site


MarshalledObject and Deserialization
 
1.MarshalledObject
2.object, MarshalledObject의 Deserialization비교
3.Dynamic class Loading - java.rmi.server.codebase property
( 2003/03/31 ) 130
Written by specular - 전홍성
1 of 1
 

  java.rmi.MarshalledObject는 Constructor의 argument에 취하는 Object의 Serialized data인 
byte stream을 갖고 있는 객체이다. 
즉 MarshalledObject는 object에 대한 Serialized representation을 갖고 있는 Container객체이다.
Member method인 get() method는 갖고있는 byte stream의 deserialization으로 original object의  
복사본 객체를 만들어 return 한다.

   MarshalledObject가 serialized data인 byte stream을 create할때 각각의 class들은 나중에 
 deserialized될때 코드가 loading될수있는 codebase URL이 표시되고, marshalled object내에 
 있는 remote object(분산객체)들은 serialized 된 stub instance로 된다. 

Serialization시에 어떤 객체를 serialize할수도 있겠지만, 그 객체의 serialized representation(byte strrem)을 
갖고 있는 MarshalledObject를 serialize할수도 있다. MarshalledObject를 serialize하는 것은 deserialize시 
MarshalledObject를 얻는 JVM에서는 MarshalledObject내 객체에 대한 class를 반드시 갖고 있어야 할 
필요가 없다는 장점을 갖게된다. 그리고, MarshalledObject는 객체에 대한 codebase url을 갖고 
있을수 있기 때문에 필요에 따라서 dynamic class loaded될수가 있다. 
(RMI의 dynamic stub loaded도 이와 같은것이겠죠!!)

자 그러면, MarshalledObject의 serialization과 deserilization을 살펴 보기 전에, Object serialization을 먼저
예제로서 보기로 하겠습니다.

Object Serialization and Deserialization

    //Serializable object 정의
    import java.io.Serializable;

    public class ObjectContainer implements Serializable 
    {
        private Object value;

        public ObjectContainer(Object value) {
            this.value=value;
        }
        public String toString() {
                return "This container holds " + value;
        }	
    }

	
    //Serialization Example
    import java.io.*;

    public class WriteObject 
    {
        public static void main(String args[]) throws Exception 
        {
            if(args.length!=1) {
                System.out.println("java -cp classes WriteObject [object.ser]");
                return;
            }
            
            FileOutputStream fo=null;
            ObjectOutputStream oos=null;
            try {
                 fo = new FileOutputStream(args[0]);
                 oos = new ObjectOutputStream(fo);
                 oos.writeObject(new ObjectContainer("HongSeong"));
            } finally {
                if(fo!=null) fo.close();
                if(oos!=null) oos.close();
            }
            System.out.println("Wrote to " + args[0]);
        }
    }
	
    //Deserialization Example
    import java.io.*;

    public class ReadObject 
    {
    public static void main(String args[]) throws Exception
    {
        if(args.length!=1) {
            System.out.println("java -cp classes ReadObject [object.ser]");
            return;
        }
        
        FileInputStream fi=null;
        ObjectInputStream ois=null;
        try {
            fi = new FileInputStream(args[0]);
            ois = new ObjectInputStream(fi);
            Object tmp = ois.readObject();
            System.out.println("Read from file " + args[0]+ ":");
            System.out.println(tmp);
        } finally {
            if(fi!=null) fi.close();
            if(ois!=null) ois.close();
        }
    }
    }
	
    [Test]
    c:\work>mkdir classes
    c:\work>javac -d classes *.java
    c:\work>java -cp classes WriteObject object.ser
        Wrote to object.ser
    c:\work>java -cp classes ReadObject object.ser
        Read from file object.ser:
        This container holds HongSeong

  Deserialization시에 ObjectContainer.class 파일이 반드시 있어야 한다는 것 정도는 아시겠죠.!!!
즉 객체를 Serialization시킬경우에는 Deserialization시 data type인 class file의 location을 classpath경로 
외에는 알수 있는 방법이 없다는 것입니다.

    [Test]
    c:\work>mkdir otherdir
    c:\work>copy classes\ReadObject.class otherdir
    c:\work>java -cp otherdir ReadObject object.ser
         java.lang.ClassNotFoundException: ObjectContainer
                at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
                (etc...)

▶2.MarshalledObject Serialization and Deserialization

    //file WriteMarshalled.java
    import java.io.*;
    import java.rmi.*;

    public class WriteMarshalled {
    public static void main(String[] args) throws IOException 
    {
        FileOutputStream fo=null;
            ObjectOutputStream oos = null;
            try {
                fo = new FileOutputStream(args[0]);
                oos = new ObjectOutputStream(fo);
                ObjectContainer container = new ObjectContainer("specular");
                MarshalledObject mo = new MarshalledObject(container);
                oos.writeObject(mo);
            } finally {
                if (fo != null) fo.close();
                if (oos != null) oos.close();
            }
            System.out.println("Wrote to " + args[0]);
    }
    }

    //file ReadMarshalled.java
    import java.io.*;
    import java.rmi.*;

    public class ReadMarshalled {
    public static void main(String[] args) throws Exception 
    {
        FileInputStream fi = null;	
            ObjectInputStream ois = null;
        try {
            fi = new FileInputStream(args[0]);
            ois = new ObjectInputStream(fi);
                MarshalledObject o = (MarshalledObject) ois.readObject();
                System.out.println("Read MarshalledObject from file " +
                            args[0]+ ", contents are:");
                Object containee = o.get();
                System.out.println(containee);
                
                System.out.println("Marshalled object loaded by: " + 
                                    o.getClass().getClassLoader());
                System.out.println("Containee loaded by: " + 
                        containee.getClass().getClassLoader());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if(fi != null) fi.close();
                if (ois != null) ois.close();
            }
    }
    }

    [Test]
    c:\work>javac -d classes *.java
  테스트를 하기전에 다시 위에서 설명한 내용을 생각해 봐야 겠다. 
MarshalledObject를 이용할 경우에는 Deserialization 결과는 MarshalledObjce가 
되고, 이 객체의 get() method를 통해 원한는 객체를 얻어 낼수가 있는 것이다.
이때, 위에서 언급한 봐와 같이, deserialization시 class의 loaction지정을 
Serialization시 MarashalledObject를 생성할때 표시 할수가 있다고 있다.
	[Test]
	c:\work>java -Djava.rmi.server.codebase=http://localhost:8080/ \
	-cp classes WriteMarshalled marshalled.ser
		Wrote to marshalled.ser

  java.rmi.server.codebase property에 의해 MarshalledObject내의 
객체에 대한 class의 location정보를 줄수가 있는것이다. 
결국 http://localhost:8080/ 경로도 runtime에 deserialization시 class를 
loading하기 위해 찾는 경로에 포함을 하게 되는 것이죠.
이것은 RMI에서 Remote Loaded Stub의 기능을 이용할때 .. RMIServer를 
start시키면서 주는 property기능과 동일한것이다. MarshalledObject를 생성하면서 
java.rmi.server.codebase property는 MarshalledObject내 정보가 넘어가게 
되는 것이다. 이것은 나중에 Deserialization시 class file을 loading하기위한 
url로 참조가 되어 진다.

  다음은 Deserialization을 테스트 해야 하는데.....

	[Test]
	1. web server를 실행하고, document root에 ObjectContainer.class file을 
	갖다 놓는다.
	
	2. otherdir에 ReadMarshalled.class file, marshalled.ser file을 copy한다.
		c:\work>copy marshalled.ser otherdir
		c:\work>copy classes\ReadMarshalled.class otherdir
		c:\work>cd otherdir
		c:\work\otherdir>dir
		    2001-05-10  07:49p               1,059 ReadObject.class
		    2001-05-10  07:55p               1,468 ReadMarshalled.class
		    2001-05-11  10:40a                 241 marshalled.ser
	3. ReadMarshalled 실행
	  c:\work\otherdir>java ReadMarshalled marshalled.ser
	 ▶ 당연히 ClassNotFoundException이 발생 하겠죠. 왜냐면,
		  
			MarshalledObject o = (MarshalledObject) ois.readObject();
      			System.out.println("Read MarshalledObject from file " +
                      			args[0]+ ", contents are:");
      			Object containee = o.get();//Exception 발생
      
      		위에서 o.get() 할때, object에 대한 byte stream을 이용해서 
      		original object를 만들어야 하는데. class file을 classpath
      		경로에서 찾을수가 없기 때문에 ClassNotFoundException이 발생하는 
      		것이죠.
      	
      	▶ Serialization시 넘겨준 codebase url를 참조하기 위해서는 SecurityManager가 
      	   Setting되어 져야 한다. classpath경로에서 class file을 loading하는 ClassLoader
      	   객체는 classpath경로 외의 다른 location에 있는 class file을 loading할수가 없다.
      	   codebase경로의 class를 loading할수 있는 ClassLoader는 JVM내의 RMI system에서
      	   제공을 하는데 이것은 SecurityManager가 setting되어 져야하는 것이죠.
      	   그래서, command line에 property option으로 security manager를 다음과 같이 
      	   setting해서 실행시킨다.
      	   
        c:\work\otherdir>java -Djava.security.manager ReadMarshalled marshalled.ser	   	
      		java.lang.ClassNotFoundException: java.security.AccessControlException: 
      		access denied (java.net.SocketPermission localhost:8080 connect,resolve)
        		at java.security.AccessControlContext.checkPermission(AccessControlConte
			xt.java:272)
        		at java.security.AccessController.checkPermission(AccessController.java:399)
        	
    ▶ 위의 에러를 보면, codebase url정보를 읽엇다는 것을 알수가 있고, 그 경로로 부터 class file을
        loading하다 security제한으로 AccessControlException이 발생된것을 알수가 있다.
        classpath경로외의 다른 system으로 부터 class file을 loading하기 위해서는 Scoket 
        permission중에 connect와 resolve permission이 부여 되어야 하는 것이죠.
        그래서, policy file을 다음과 같이 만들어 현재 dir에 저장 한다.
         	
        /* AUTOMATICALLY GENERATED ON Fri May 11 09:38:40 GMT+09:00 2001*/
        /* DO NOT EDIT simple.policy file*/
        grant {
          permission java.net.SocketPermission "localhost:1024-", "resolve, connect";
        };

        c:\work\otherdir>java -Djava.security.policy=simple.policy \
        -Djava.security.manager ReadMarshalled marshalled.ser	   	
            manager ReadMarshalled marshalled.ser
        Read MarshalledObject from file marshalled.ser, contents are:
        This container holds specular
        Marshalled object loaded by:null
        Containee loaded by: sun.rmi.server.LoaderHandler$Loader@7c4bec 	 		

    ▶ ReadMarshalled source와 실행 결과를 보면, Remote에 있던 ObjectContainer.class
      file을 Loading한 ClassLoader는 rmi system에서 제공하는 LoaderHadler의 inner
      class인 Loader라는 것을 알수가 있다. - Dynamic ClassLoader라고 합니다.

  MarshalledObject의 Serialization을 정리해 봤는데, sun site의 developer site에 Tech. 
TIP의 내용을정리한것입니다. 
Remote Method Invocation의 내부 Mechanism 이해에 도움이 되었으면 합니다.
2001.05.11 written by Jeon HongSeong
 
1
References
 
Copyright ⓒ 2003 www.javapattern.info & www.jlook.com, an jLOOK co.,LTD