ChipShop
以下のコードには、 (サーバー) と(クライアント)の 2 つのアプリを使用した単純な Akka リモート アクターの例が含まれていCustomer
ます。印刷された注文を顧客が送信すると、そのままで問題なく動作ChipShopOrder
しますが、Enum を使用するように実装を切り替えると、例外 (java.io.IOException:unexpected exception type) が発生します。どうしてこれなの?
例外:
[INFO] [06/21/2012 19:40:54.1] [main] [ActorSystem(ShopSystem)] REMOTE: RemoteServerStarted@akka://ShopSystem@127.0.0.1:2552
[INFO] [06/21/2012 19:41:03.692] [ShopSystem-7] [ActorSystem(ShopSystem)] REMOTE: RemoteClientStarted@akka://CustomerSystem@127.0.0.1:2553
[ERROR] [06/21/2012 19:41:03.796] [ShopSystem-3] [ActorSystem(ShopSystem)] REMOTE: RemoteServerError@akka://ShopSystem@127.0.0.1:2552] Error[java.io.IOException:unexpected exception type
at java.io.ObjectStreamClass.throwMiscException(ObjectStreamClass.java:1518)
at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1097)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1780)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at scala.collection.mutable.HashTable$class.init(HashTable.scala:81)
at scala.collection.mutable.HashMap.init(HashMap.scala:45)
at scala.collection.mutable.HashMap.readObject(HashMap.scala:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1004)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1866)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at akka.serialization.JavaSerializer$$anonfun$1.apply(Serializer.scala:121)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:57)
at akka.serialization.JavaSerializer.fromBinary(Serializer.scala:121)
at akka.serialization.Serialization.deserialize(Serialization.scala:73)
at akka.remote.MessageSerializer$.deserialize(MessageSerializer.scala:21)
at akka.remote.RemoteMessage.payload(RemoteTransport.scala:210)
at akka.remote.RemoteMarshallingOps$class.receiveMessage(RemoteTransport.scala:276)
at akka.remote.netty.NettyRemoteTransport.receiveMessage(NettyRemoteSupport.scala:29)
at akka.remote.netty.RemoteServerHandler.messageReceived(Server.scala:178)
at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75)
at akka.remote.netty.RemoteServerHandler.handleUpstream(Server.scala:150)
at org.jboss.netty.channel.StaticChannelPipeline.sendUpstream(StaticChannelPipeline.java:366)
at org.jboss.netty.channel.StaticChannelPipeline$StaticChannelHandlerContext.sendUpstream(StaticChannelPipeline.java:528)
at org.jboss.netty.handler.execution.ChannelUpstreamEventRunnable.run(ChannelUpstreamEventRunnable.java:44)
at org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor$ChildExecutor.run(OrderedMemoryAwareThreadPoolExecutor.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
実行するには、まず ChipShop アプリを起動し、次に Customer アプリを起動します。ソース:
import com.typesafe.config.ConfigFactory
import akka.actor.{ ActorSystem, Actor, Props }
object Configs{
val customerConfig = ConfigFactory.parseString( """
akka.actor.provider = akka.remote.RemoteActorRefProvider
akka.remote.netty.hostname = "127.0.0.1"
akka.remote.netty.port = 2553
""")
val shopConfig = ConfigFactory.parseString( """
akka.actor.provider = akka.remote.RemoteActorRefProvider
akka.remote.netty.hostname = "127.0.0.1"
akka.remote.netty.port = 2552
""")
}
class ChipShopOrder extends Serializable{
// - Working implementation -
trait Food
case object Chips extends Food
case object Fish extends Food
case class OrderableItem(item: Food, quantity: Int)
//----------- End -----------
// -- Broken implementation --
// object Food extends Enumeration{
// type Food = Value
// val Chips, Fish, Sausage = Value
// }
// import Food._
// case class OrderableItem(item: Food.Value, quantity: Int)
//----------- End ------------
case class CustomerOrder(items: Seq[OrderableItem])
val anOrder = CustomerOrder(Seq(
OrderableItem(Chips, 2), OrderableItem(Fish, 1)
))
}
object Customer extends App{
val system = ActorSystem("CustomerSystem", Configs.customerConfig)
val shopAddress = "akka://ShopSystem@127.0.0.1:2552/user/Staff"
system.actorFor(shopAddress) ! new ChipShopOrder().anOrder
}
object ChipShop extends App{
class Staff extends Actor{
def receive = { case order => println("Received: "+order) }
}
ActorSystem("ShopSystem", Configs.shopConfig).actorOf(Props[Staff], "Staff")
}