é·ãéãç§ã¯èªåã®ç¥èãã³ãã¥ããã£ãšå ±æããããšãèããŠããŸããã æåã¯ã倩äœç©çåŠãGTRã«ã€ããŠäœããæžãããã£ãã®ã§ãããããã§ãç§ã¯å°éçã«æ±ã£ãŠãããã®äž»é¡åéã«ã€ããŠæžãæ¹ãæ£ãããšå€æããŸããã ãã®ãããAndroidåãã²ãŒã ã¢ããªã±ãŒã·ã§ã³ã®äœæããã»ã¹ãšå®è£ ã®åŸ®åŠãªç¹ïŒèšèšããå ¬éãã¢ããªå è³Œå ¥ãŸã§ïŒã詳现ã«èª¬æããããšããŸãã
ã¯ããã«
ç§ã¯æåã®ã¯ã©ã¹ããããã°ã©ãã³ã°ã«åŸäºãããµã³ã¯ãããã«ãã«ã¯å·ç«å·¥ç§å€§åŠã®å¿çšæ°åŠãåæ¥ããŸããã æè¿ïŒçŽ1幎åïŒãã¢ãã€ã«ãã©ãããã©ãŒã ã®éçºãçºèŠããŸããã ãããäœã§ãäœã§é£ã¹ãããã®ããé¢çœããªã£ãŠããŸããã çŸåšãå人/ååã®ããŒã ã§ããã€ãã®ãããžã§ã¯ããéçºããŠããŸãããæåã®çµéšã«ã€ããŠæžããããšæããŸãã ãã®ãããªçµéšã¯ãã²ãŒã ã¢ããªã±ãŒã·ã§ã³-ã ã¹ããã«ãŒ ãïŒç§ã¯èª°ã§ããïŒïŒãäœæããããšã§ããã
ãããã¯ã©ã®ãããªã¹ããã«ãŒã§ããïŒ
ç¥ããªã人ã®ããã«-ç§ã¯èª¬æããŸãã ã¹ããã«ãŒ-ããã¯ãã®ãããªããŒãã«ã²ãŒã ã§ãåãã¬ã€ã€ãŒã¯é¡ã«æåãªãã£ã©ã¯ã¿ãŒãããçŽã1æãã€åãåããŸãïŒãã¬ã€ãããã£ã©ã¯ã¿ãŒã¯äºãã«ç»å ŽããŸãïŒã ååå è
ã®ç®æšã¯ãèªåãæšæž¬ãããã£ã©ã¯ã¿ãŒãæšæž¬ããããšã§ãã
ã²ãŒã ãã¬ã€ã¯ã質åã®é£ç¶çãªyes / noã¿ã¹ã¯ã§ãããä»ã®ãã¬ã€ã€ãŒããããããžã®åçãåãåããŸãã
ã²ãŒã ãã¬ã€ã¯ã質åã®é£ç¶çãªyes / noã¿ã¹ã¯ã§ãããä»ã®ãã¬ã€ã€ãŒããããããžã®åçãåãåããŸãã
ããã€ãã®çç±ã«ãããã¹ããã«ãŒãéžã°ããŸããã
ãŸããåžå Žã«é¡äŒŒç©ãèŠã€ãããŸããã§ããïŒããã¯ã説æããããŒãã«ã²ãŒã ã®ã«ãŒã«ã®å®è£ ãæããŸãïŒã
第äºã«ãç§ã¯éåžžã«æéãããããªããã®ãæžãããã£ãã
第äžã«ããã®ã²ãŒã ã¯ç§ãã¡ã®ãµãŒã¯ã«ã§éåžžã«äººæ°ãããããããã誰ãããããå®éã«ãã¬ã€ããããšæããšæããŸããã
éçºããã»ã¹
åé¡ã®å£°æ
ã¿ã¹ã¯ã¯éåžžã«æ確ã«åœ¢æãããŸããã ãŠãŒã¶ãŒã次ã®æ©èœã䜿çšã§ããããã«ããã¯ã©ã€ã¢ã³ã/ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ãå®è£ ããå¿ èŠããããŸãã
- ç¬èªã®ã¢ã«ãŠã³ããäœæãã
- èªåã®ã¢ã«ãŠã³ãã䜿çšããèªèšŒ
- ãã¬ã€ã€ãŒã©ã³ãã³ã°ãèŠã
- ã²ãŒã ã«ãŒã ãäœæãã
- ã²ãŒã ã«ãŒã ãžã®å ¥ãå£
- ã²ãŒã ãã¬ã€åå
ã²ãŒã ãã¬ã€ã¯çžå€åã§ãïŒ
- 質åãã§ãŒãº
- æ祚ãã§ãŒãº
UIãã¶ã€ã³
幞ããªããšã«ãç§ã®åŠ»ã¯ãã¶ã€ããŒã§ããããã¬ãããèŠçŽ ã®é 眮ããã®ä»ã®ãã¶ã€ããŒã®ãã®ãéžæããããšã«å®éã«åå ããå¿ èŠã¯ãããŸããã§ããã ã²ãŒã ããã¬ãŒã€ãŒã«æäŸããå¿ èŠãããæ©èœã®åæã«åºã¥ããŠãã²ãŒã ã®ç¶æ ïŒã¢ã¯ãã£ããã£ïŒã®æ°ãšåã²ãŒã ã®ç¶æ ã«å¿ èŠãªã³ã³ãããŒã«ã決å®ããŸããã
- ã¡ã€ã³ã¡ãã¥ãŒ
- èªèšŒ
- ç»é²
- ãã¬ãŒã€ãŒã®è©äŸ¡ãžã®ã¢ã¯ã»ã¹
- ãã¬ã€ã€ãŒã®è©äŸ¡
- ã¡ã€ã³ã¡ãã¥ãŒã«æ»ããŸãã
- éšå±ãªã¹ã
- éšå±ãžã®å ¥ãå£
- èªåã®éšå±ãäœæãã
- ã¡ã€ã³ã¡ãã¥ãŒã«ç§»åããŸã
- çŸåšã®éšå±
- éšå±ãåºã
- ã²ãŒã ç¶æ
çªå·1ïŒå
¥å質å
- 質åãå ¥åãã
- 質åã®æŽå²ãžã®ç§»è¡
- åçå ¥åã«ç§»å
- ã¡ã€ã³ã¡ãã¥ãŒã«ç§»åããŸã
- ã²ãŒã ã®ç¶æ
No. 2ïŒè³ªåã®å±¥æŽã衚瀺ãã
- 質åã®å ¥åã«ç§»å
- åçå ¥åã«ç§»å
- ã¡ã€ã³ã¡ãã¥ãŒã«ç§»åããŸã
- ã²ãŒã ç¶æ
No. 3ïŒå
¥åå¿ç
- å¿çå ¥å
- 質åã®å ¥åã«ç§»å
- 質åã®æŽå²ãžã®ç§»è¡
- ã¡ã€ã³ã¡ãã¥ãŒã«ç§»åããŸã
- ã²ãŒã ã®ç¶æ
No. 4ïŒæ祚
- é³å£°å ¥å
- ã¡ã€ã³ã¡ãã¥ãŒã«ç§»åããŸã
- åå©
- ã¡ã€ã³ã¡ãã¥ãŒã«ç§»åããŸã
- åã
- ãŠã£ãããã£ã¢ã«ç§»åïŒãã£ã©ã¯ã¿ãŒããŒãžãžïŒ
- ã¡ã€ã³ã¡ãã¥ãŒã«ç§»åããŸã
ç¶æ
é·ç§»å³
DBãã¶ã€ã³
ã²ãŒã å ã«ã©ã®ã²ãŒã ç¶æ ãšãªããžã§ã¯ããååšããããæããã«ãªã£ããããã«ãããŒã¿ããŒã¹ã®èŠ³ç¹ãããããã圢åŒåããããšã«é²ã¿ãŸããã
ãã®ããã次ã®è¡šãå¿ èŠã§ãã
- ãŠãŒã¶ãŒ ãã¹ãŠã®ãŠãŒã¶ãŒã«é¢ããæ å ±ãæ ŒçŽããããŒãã«
- ã²ãŒã ãã¹ãŠã®éšå±ã«é¢ããæ å ±ãæ ŒçŽããããŒãã«
- ãã£ã©ã¯ã¿ãŒã ãã¹ãŠã®ãã£ã©ã¯ã¿ãŒã«é¢ããæ å ±ãä¿åããããŒãã«
- 質åã 圌ãäœã£ããã£ã©ã¯ã¿ãŒã«é¢ãããŠãŒã¶ãŒã®è³ªåãä¿åããããŒãã«
- åç ãŠãŒã¶ãŒã®å¿çãä¿åãããããŒãã«
ã²ãŒã ã®åæããŒãžã§ã³ã«ã¯ãããã®ããŒãã«ãããããŸããã§ããããã²ãŒã ãéçºãããæ°ããããŒãã«ãè¿œå ãããŸããã æ®ãã®ããŒãã«ã«ã€ããŠã¯èª¬æããŸãããããããªããšããã¬ãŒã·ã§ã³ãéåžžã«é·ããªããŸãã ãã¹ãŠã®ããŒãã«ã¯ããŒã¿ããŒã¹ãã€ã¢ã°ã©ã ã«è¡šç€ºãããŸãããããŒãã«ãååšããŠããã以äžã®è°è«ã劚ããããšã¯ãããŸããã
ããŒãã«éã®é¢ä¿ã¯æ°åïŒããã°ã¢ãžã£ã€ã«ïŒå€æŽãããŸããããæçµçã«ã¯æ¬¡ã®ããã«ãªããŸããã
- åãŠãŒã¶ãŒã¯1人ã®ãã£ã©ã¯ã¿ãŒã«é¢é£ä»ããããšãã§ããŸãã
- åãŠãŒã¶ãŒã¯1ã€ã®éšå±ã«ããå ¥å®€ã§ããŸããã
- å質åã¯1人ã®ãŠãŒã¶ãŒã®ã¿ã質åã§ããŸãã
- å質åã¯ã1人ã®ãã£ã©ã¯ã¿ãŒã«ã®ã¿é¢é£ä»ããããšãã§ããŸãã
- å質åã¯1ã€ã®ã²ãŒã å ã§ã®ã¿è³ªåã§ããŸãã
- ååçã¯1人ã®ãŠãŒã¶ãŒã®ã¿ãæå®ã§ããŸãã
- ååçã¯1ã€ã®è³ªåã«ã®ã¿äžããããšãã§ããŸãã
ãããŠãããŒã¿ã®æ£èŠåã¯ã©ãã«ãããŸããïŒ
éè€ããéä¿¡ã¯ãDBMSã®è² è·ã軜æžããããã«ã®ã¿å¿
èŠã§ãããã²ãŒã ã®æåã®ããŒãžã§ã³ããã¯ã»ã©é ãããã«èŠããŸããã ããŒãã«ã®æ°ã®å¢å ã«äŒŽããç¹å®ã®ããŒã¿ãµã³ãã«ã«å¯ŸããŠå®è¡ããå¿
èŠã®ããéèšã®æ°ãå¢å ããŸããã
ã¢ããªã±ãŒã·ã§ã³ã¬ãã«
æåŸã«ããœãããŠã§ã¢ã®å®è£ ã«å°éããŸããã ã ãããç§ã¯æãäžè¬çãªèšèããå§ããŸãã ãããžã§ã¯ãå šäœã¯4ã€ã®ã¢ãžã¥ãŒã«ã§æ§æãããŠããŸãã
- ãã³ã¿ã 䟿å©ãªãŠãŒãã£ãªãã£ãã³ã³ãã€ã«ããã©ã€ãã©ãª
- ãããã³ã«ã çžäºäœçšãããã³ã«ã®èª¬æãå«ãã©ã€ãã©ãª
- ãµãŒã㌠ã¢ããªã±ãŒã·ã§ã³ãµãŒããŒ
- ã¯ã©ã€ã¢ã³ã ã¢ããªã±ãŒã·ã§ã³ã®ã¯ã©ã€ã¢ã³ãåŽ
ãããžã§ã¯ãæŠèŠ
ãã³ã¿å³æžé€š
ç§ã¯è»èŒªãåçºæããã®ã奜ãã§ããµãŒãããŒãã£ã®ã©ã€ãã©ãªã®ããŸãããå«ããªã®ã§ïŒãããå€ãã®éå±ãªããã°ã©ããŒã®å€å žçãªåé¡ïŒãç§ã¯èªåã§äœããæžãããšã«ããŸããã ç§ã¯ãã®ã©ã€ãã©ãªãé·ãéæžããŠãããç§ã«ãšã£ãŠå€ãã®æçšãªãŠãŒãã£ãªãã£ãå«ãŸããŠããŸãïŒããŒã¿ããŒã¹ãã¯ã©ã€ã¢ã³ã/ãµãŒããŒçžäºäœçšãã¢ã¯ã¿ãŒãæ°åŠãæå·åãªã©ïŒã
ãã®èšäºã§ã¯ããã®ã©ã€ãã©ãªã®ãããã¯ãŒã¯éšåã«ã€ããŠã話ããããšæããŸãã ç§ã¯ããªã¯ãšã¹ããšåçããããªããžã§ã¯ããã·ãªã¢ã©ã€ãº/ãã·ãªã¢ã©ã€ãºããããšã«ãããã¯ã©ã€ã¢ã³ããšãµãŒããŒéã®çžäºäœçšãå®è£ ããããšã«ããŸããã Messageãªããžã§ã¯ãã¯ã転éãããåºæ¬æ å ±åäœã§ãïŒãã¡ãããã©ã€ãã©ãªã¬ãã«ã§ïŒã
ãMessage.javaã
package com.gesoftware.venta.network.model; import com.gesoftware.venta.utility.CompressionUtility; import java.nio.charset.Charset; import java.io.Serializable; import java.util.Arrays; /* * * Message class definition * */ public final class Message implements Serializable { /* Time */ private final long m_Timestamp; /* Message data */ private final byte[] m_Data; /* * * METHOD: Message class constructor * PARAM: [IN] data - bytes array data * AUTHOR: Eliseev Dmitry * */ public Message(final byte data[]) { m_Timestamp = System.currentTimeMillis(); m_Data = data; } /* End of 'Message::Message' method */ /* * * METHOD: Message class constructor * PARAM: [IN] data - bytes array data * AUTHOR: Eliseev Dmitry * */ public Message(final String data) { this(data.getBytes()); } /* End of 'Message::Message' method */ /* * * METHOD: Message class constructor * PARAM: [IN] object - some serializable object * AUTHOR: Eliseev Dmitry * */ public Message(final Object object) { this(CompressionUtility.compress(object)); } /* End of 'Message::Message' method */ /* * * METHOD: Bytes data representation getter * RETURN: Data bytes representation * AUTHOR: Eliseev Dmitry * */ public final byte[] getData() { return m_Data; } /* End of 'Message::getData' method */ /* * * METHOD: Gets message size * RETURN: Data size in bytes * AUTHOR: Eliseev Dmitry * */ public final int getSize() { return (m_Data != null)?m_Data.length:0; } /* End of 'Message::getSize' method */ @Override public final String toString() { return (m_Data != null)?new String(m_Data, Charset.forName("UTF-8")):null; } /* End of 'Message::toString' method */ /* * * METHOD: Compares two messages sizes * RETURN: TRUE if messages has same sizes, FALSE otherwise * PARAM: [IN] message - message to compare with this one * AUTHOR: Eliseev Dmitry * */ private boolean messagesHasSameSizes(final Message message) { return m_Data != null && m_Data.length == message.m_Data.length; } /* End of 'Message::messagesHasSameSize' method */ /* * * METHOD: Compares two messages by their values * RETURN: TRUE if messages has same sizes, FALSE otherwise * PARAM: [IN] message - message to compare with this one * AUTHOR: Eliseev Dmitry * */ private boolean messagesAreEqual(final Message message) { /* Messages has different sizes */ if (!messagesHasSameSizes(message)) return false; /* At least one of characters is not equal to same at another message */ for (int i = 0; i < message.m_Data.length; i++) if (m_Data[i] != message.m_Data[i]) return false; /* Messages are equal */ return true; } /* End of 'Message::messagesAreEqual' method */ /* * * METHOD: Tries to restore object, that may be packed in message * RETURN: Restored object if success, null otherwise * AUTHOR: Eliseev Dmitry * */ public final Object getObject() { return CompressionUtility.decompress(m_Data); } /* End of 'Message::getObject' method */ /* * * METHOD: Gets message sending time (in server time) * RETURN: Message sending time * AUTHOR: Eliseev Dmitry * */ public final long getTimestamp() { return m_Timestamp; } /* End of 'Message::getTimestamp' method */ @Override public final boolean equals(Object obj) { return obj instanceof Message && messagesAreEqual((Message) obj); } /* End of 'Message::equals' method */ @Override public final int hashCode() { return Arrays.hashCode(m_Data); } /* End of 'Message::hashCode' method */ } /* End of 'Message' class */
ãã®ãªããžã§ã¯ãã®èª¬æã«ã€ããŠã¯è©³ãã説æããŸããããã³ãŒãã¯éåžžã«ã³ã¡ã³ããããŠããŸãã
ãããã¯ãŒã¯ã§ã®äœæ¥ã®ç°¡çŽ åã¯ã次ã®2ã€ã®ã¯ã©ã¹ã®äœ¿çšã«ãããã®ã§ãã
- ãµãŒããŒïŒãµãŒããŒåŽïŒ
- æ¥ç¶ïŒã¯ã©ã€ã¢ã³ãåŽïŒ
ã¿ã€ãServerã®ãªããžã§ã¯ããäœæããå Žåãçä¿¡æ¥ç¶ãåŸ æ©ããããŒããšIServerHandlerã€ã³ã¿ãŒãã§ãŒã¹ã®å®è£ ãæå®ããå¿ èŠããããŸã
ãIServerHandler.javaã
package com.gesoftware.venta.network.handlers; import com.gesoftware.venta.network.model.Message; import com.gesoftware.venta.network.model.ServerResponse; import java.net.InetAddress; /* Server handler interface declaration */ public interface IServerHandler { /* * * METHOD: Will be called right after new client connected * RETURN: True if you accept connected client, false if reject * PARAM: [IN] clientID - client identifier (store it somewhere) * PARAM: [IN] clientAddress - connected client information * AUTHOR: Eliseev Dmitry * */ public abstract boolean onConnect(final String clientID, final InetAddress clientAddress); /* * * METHOD: Will be called right after server accept message from any connected client * RETURN: Response (see ServerResponse class), or null if you want to disconnect client * PARAM: [IN] clientID - sender identifier * PARAM: [IN] message - received message * AUTHOR: Eliseev Dmitry * */ public abstract ServerResponse onReceive(final String clientID, final Message message); /* * * METHOD: Will be called right after any client disconnected * PARAM: [IN] clientID - disconnected client identifier * AUTHOR: Eliseev Dmitry * */ public abstract void onDisconnect(final String clientID); } /* End of 'IServerHandler' interface */
ã¯ã©ã€ã¢ã³ãã¯ã Connectionã¿ã€ãã®ãªããžã§ã¯ããäœæãããšãã«ã IClientHandlerã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ãæäŸããå¿ èŠããããŸãã
ãIClientHandler.javaã
package com.gesoftware.venta.network.handlers; import com.gesoftware.venta.network.model.Message; import com.gesoftware.venta.network.model.ServerResponse; import java.net.InetAddress; /* Server handler interface declaration */ public interface IServerHandler { /* * * METHOD: Will be called right after new client connected * RETURN: True if you accept connected client, false if reject * PARAM: [IN] clientID - client identifier (store it somewhere) * PARAM: [IN] clientAddress - connected client information * AUTHOR: Eliseev Dmitry * */ public abstract boolean onConnect(final String clientID, final InetAddress clientAddress); /* * * METHOD: Will be called right after server accept message from any connected client * RETURN: Response (see ServerResponse class), or null if you want to disconnect client * PARAM: [IN] clientID - sender identifier * PARAM: [IN] message - received message * AUTHOR: Eliseev Dmitry * */ public abstract ServerResponse onReceive(final String clientID, final Message message); /* * * METHOD: Will be called right after any client disconnected * PARAM: [IN] clientID - disconnected client identifier * AUTHOR: Eliseev Dmitry * */ public abstract void onDisconnect(final String clientID); } /* End of 'IServerHandler' interface */
ãµãŒããŒã®å éšæ§é ã«ã€ããŠå°ã説æããŸãã 次ã®ã¯ã©ã€ã¢ã³ãããµãŒããŒã«åå ãããšããã«ãäžæã®ããã·ã¥ãèšç®ãããåä¿¡ã¹ããªãŒã ãšéä¿¡ã¹ããªãŒã ã®2ã€ã®ã¹ããªãŒã ãäœæãããŸãã åä¿¡ã¹ããªãŒã ã¯ãããã¯ãããã¯ã©ã€ã¢ã³ãããã®ã¡ãã»ãŒãžãåŸ ã¡ãŸãã ã¯ã©ã€ã¢ã³ãããã®ã¡ãã»ãŒãžãåä¿¡ããããšããã«ãã©ã€ãã©ãªãŠãŒã¶ãŒãç»é²ãããã³ãã©ãŒã«éä¿¡ãããŸãã åŠçã®çµæã次ã®5ã€ã®ã€ãã³ãã®ãããããçºçããå ŽåããããŸãã
- ã¯ã©ã€ã¢ã³ãã®åæïŒåæèŠæ±ãå°çãããšããŸãããïŒ
- ã¯ã©ã€ã¢ã³ããžã®å¿çã®éä¿¡
- å¥ã®ã¯ã©ã€ã¢ã³ãã«å¿çãéä¿¡ãã
- æ¥ç¶ãããŠãããã¹ãŠã®ã¯ã©ã€ã¢ã³ãã«å¿çãéä¿¡ãã
- ç¹å®ã®ã¯ã©ã€ã¢ã³ãã°ã«ãŒãã«å¿çãéä¿¡ãã
æ¥ç¶ãããã¯ã©ã€ã¢ã³ãã®1ã€ã«ã¡ãã»ãŒãžãéä¿¡ããå¿ èŠãããå Žåããã®ã¯ã©ã€ã¢ã³ãã®ã¡ãã»ãŒãžéä¿¡ãã¥ãŒã«é 眮ãããéä¿¡ãæ åœããã¹ã¬ããã«æ°ããã¡ãã»ãŒãžããã¥ãŒã«è¡šç€ºãããããšãéç¥ãããŸãã
æããã«ãããŒã¿ãããŒã¯æ¬¡ã®å³ã§ç€ºãããšãã§ããŸãã
ã©ã€ãã©ãªã®ãããã¯ãŒã¯ã¢ãžã¥ãŒã«ã§ã®ããŒã¿ãããŒ
ã¯ã©ã€ã¢ã³ãXã¯ãµãŒããŒã«ãªã¯ãšã¹ããéä¿¡ããŸãïŒèµ€ãç¢å°ïŒã èŠæ±ã¯ãã¯ã©ã€ã¢ã³ãã«å¯Ÿå¿ããã¬ã·ãŒããŒã¹ããªãŒã ã§åä¿¡ãããŸãã ããã«ã¡ãã»ãŒãžãã³ãã©ãåŒã³åºããŸãïŒé»è²ã®ç¢å°ïŒã åŠçã®çµæãç¹å®ã®å¿çã圢æãããã¯ã©ã€ã¢ã³ãXã®éä¿¡ãã¥ãŒã«é 眮ãããŸãïŒç·è²ã®ç¢å°ïŒã éä¿¡ã¹ããªãŒã ã¯ãéä¿¡ãã¥ãŒå ã®ã¡ãã»ãŒãžã確èªãïŒé»ãç¢å°ïŒãã¯ã©ã€ã¢ã³ãã«å¿çãéä¿¡ããŸãïŒéãç¢å°ïŒã
äŸïŒãã«ããŠãŒã¶ãŒãšã³ãŒãµãŒããŒïŒ
package com.gesoftware.venta.network; import com.gesoftware.venta.logging.LoggingUtility; import com.gesoftware.venta.network.handlers.IClientHandler; import com.gesoftware.venta.network.handlers.IServerHandler; import com.gesoftware.venta.network.model.Message; import com.gesoftware.venta.network.model.ServerResponse; import java.net.InetAddress; import java.util.TimerTask; public final class NetworkTest { private final static int c_Port = 5502; private static void startServer() { final Server server = new Server(c_Port, new IServerHandler() { @Override public boolean onConnect(final String clientID, final InetAddress clientAddress) { LoggingUtility.info("Client connected: " + clientID); return true; } @Override public ServerResponse onReceive(final String clientID, final Message message) { LoggingUtility.info("Client send message: " + message.toString()); return new ServerResponse(message); } @Override public void onDisconnect(final String clientID) { LoggingUtility.info("Client disconnected: " + clientID); } }); (new Thread(server)).start(); } private static class Task extends TimerTask { private final Connection m_Connection; public Task(final Connection connection) { m_Connection = connection; } @Override public void run() { m_Connection.send(new Message("Hello, current time is: " + System.currentTimeMillis())); } } private static void startClient() { final Connection connection = new Connection("localhost", c_Port, new IClientHandler() { @Override public void onReceive(final Message message) { LoggingUtility.info("Server answer: " + message.toString()); } @Override public void onConnectionLost(final String message) { LoggingUtility.info("Connection lost: " + message); } }); connection.connect(); (new java.util.Timer("Client")).schedule(new Task(connection), 0, 1000); } public static void main(final String args[]) { LoggingUtility.setLoggingLevel(LoggingUtility.LoggingLevel.LEVEL_DEBUG); startServer(); startClient(); } }
ããªãçãã§ããã
ã²ãŒã ãµãŒããŒ
ã²ãŒã ãµãŒããŒã®ã¢ãŒããã¯ãã£ã¯ãã«ãã¬ãã«ã§ãã ããã«ç§ã¯åœŒå¥³ã®ã¹ããŒã ãšããã®åŸã®èª¬æãããŸãã
ãµãŒããŒã¢ãŒããã¯ãã£å³
ãã®ãããããŒã¿ããŒã¹ãšã®å¯Ÿè©±ã«ã¯æ¥ç¶ããŒã«ã䜿çšãããŸãïŒç§ã¯BoneCPã©ã€ãã©ãªã䜿çšããŠããŸãïŒã ããªãã¢ãã¹ããŒãã¡ã³ãã䜿çšããããã«ãæ¥ç¶ãèªåã®ã¯ã©ã¹ïŒVentaã©ã€ãã©ãªïŒã§ã©ããããŸããã
DBConnection.java
package com.gesoftware.venta.db; import com.gesoftware.venta.logging.LoggingUtility; import com.jolbox.bonecp.BoneCPConfig; import com.jolbox.bonecp.BoneCP; import java.io.InputStream; import java.util.AbstractList; import java.util.LinkedList; import java.util.HashMap; import java.util.Map; import java.sql.*; /** * DB connection class definition **/ public final class DBConnection { /* Connections pool */ private BoneCP m_Pool; /** * DB Statement class definition **/ public final class DBStatement { private final PreparedStatement m_Statement; private final Connection m_Connection; /* * * METHOD: Class constructor * PARAM: [IN] connection - current connection * PARAM: [IN] statement - statement, created from connection * AUTHOR: Dmitry Eliseev * */ private DBStatement(final Connection connection, final PreparedStatement statement) { m_Connection = connection; m_Statement = statement; } /* End of 'DBStatement::DBStatement' class */ /* * * METHOD: Integer parameter setter * RETURN: True if success, False otherwise * PARAM: [IN] index - parameter position * PARAM: [IN] value - parameter value * AUTHOR: Dmitry Eliseev * */ public final boolean setInteger(final int index, final int value) { try { m_Statement.setInt(index, value); return true; } catch (final SQLException e) { LoggingUtility.debug("Can't set integer value: " + value + " because of " + e.getMessage()); } return false; } /* End of 'DBStatement::setInteger' class */ /* * * METHOD: Long parameter setter * RETURN: True if success, False otherwise * PARAM: [IN] index - parameter position * PARAM: [IN] value - parameter value * AUTHOR: Dmitry Eliseev * */ public final boolean setLong(final int index, final long value) { try { m_Statement.setLong(index, value); return true; } catch (final SQLException e) { LoggingUtility.debug("Can't set long value: " + value + " because of " + e.getMessage()); } return false; } /* End of 'DBStatement::setLong' class */ /* * * METHOD: String parameter setter * RETURN: True if success, False otherwise * PARAM: [IN] index - parameter position * PARAM: [IN] value - parameter value * AUTHOR: Dmitry Eliseev * */ public final boolean setString(final int index, final String value) { try { m_Statement.setString(index, value); } catch (final SQLException e) { LoggingUtility.debug("Can't set string value: " + value + " because of " + e.getMessage()); } return false; } /* End of 'DBStatement::setString' class */ /* * * METHOD: Enum parameter setter * RETURN: True if success, False otherwise * PARAM: [IN] index - parameter position * PARAM: [IN] value - parameter value * AUTHOR: Dmitry Eliseev * */ public final boolean setEnum(final int index, final Enum value) { return setString(index, value.name()); } /* End of 'DBStatement::setEnum' method */ /* * * METHOD: Binary stream parameter setter * RETURN: True if success, False otherwise * PARAM: [IN] index - parameter position * PARAM: [IN] stream - stream * PARAM: [IN] long - data length * AUTHOR: Dmitry Eliseev * */ public final boolean setBinaryStream(final int index, final InputStream stream, final long length) { try { m_Statement.setBinaryStream(index, stream); return true; } catch (final SQLException e) { LoggingUtility.debug("Can't set stream value: " + stream + " because of " + e.getMessage()); } return false; } /* End of 'DBStatement::setBinaryStream' method */ } /* End of 'DBConnection::DBStatement' class */ /* * * METHOD: Class constructor * PARAM: [IN] host - Database service host * PARAM: [IN] port - Database service port * PARAM: [IN] name - Database name * PARAM: [IN] user - Database user's name * PARAM: [IN] pass - Database user's password * AUTHOR: Dmitry Eliseev * */ public DBConnection(final String host, final int port, final String name, final String user, final String pass) { final BoneCPConfig config = new BoneCPConfig(); config.setJdbcUrl("jdbc:mysql://" + host + ":" + port + "/" + name); config.setUsername(user); config.setPassword(pass); /* Pool size configuration */ config.setMaxConnectionsPerPartition(5); config.setMinConnectionsPerPartition(5); config.setPartitionCount(1); try { m_Pool = new BoneCP(config); } catch (final SQLException e) { LoggingUtility.error("Can't initialize connections pool: " + e.getMessage()); m_Pool = null; } } /* End of 'DBConnection::DBConnection' method */ @Override protected final void finalize() throws Throwable { super.finalize(); if (m_Pool != null) m_Pool.shutdown(); } /* End of 'DBConnection::finalize' method */ /* * * METHOD: Prepares statement using current connection * RETURN: Prepared statement * PARAM: [IN] query - SQL query * AUTHOR: Dmitry Eliseev * */ public final DBStatement createStatement(final String query) { try { LoggingUtility.debug("Total: " + m_Pool.getTotalCreatedConnections() + "; Free: " + m_Pool.getTotalFree() + "; Leased: " + m_Pool.getTotalLeased()); final Connection connection = m_Pool.getConnection(); return new DBStatement(connection, connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)); } catch (final SQLException e) { LoggingUtility.error("Can't create prepared statement using query: " + e.getMessage()); } catch (final Exception e) { LoggingUtility.error("Connection wasn't established: " + e.getMessage()); } return null; } /* End of 'DBConnection::createStatement' method */ /* * * METHOD: Closes prepared statement * PARAM: [IN] sql - prepared statement * AUTHOR: Dmitry Eliseev * */ private void closeStatement(final DBStatement query) { if (query == null) return; try { if (query.m_Statement != null) query.m_Statement.close(); if (query.m_Connection != null) query.m_Connection.close(); } catch (final SQLException ignored) {} } /* End of 'DBConnection::closeStatement' method */ /* * * METHOD: Executes prepared statement like INSERT query * RETURN: Inserted item identifier if success, 0 otherwise * PARAM: [IN] sql - prepared statement * AUTHOR: Dmitry Eliseev * */ public final long insert(final DBStatement query) { try { /* Query execution */ query.m_Statement.execute(); /* Obtain last insert ID */ final ResultSet resultSet = query.m_Statement.getGeneratedKeys(); if (resultSet.next()) return resultSet.getInt(1); } catch (final SQLException e) { LoggingUtility.error("Can't execute insert query: " + query.toString()); } finally { closeStatement(query); } /* Insertion failed */ return 0; } /* End of 'DBConnection::insert' method */ /* * * METHOD: Executes prepared statement like UPDATE query * RETURN: True if success, False otherwise * PARAM: [IN] sql - prepared statement * AUTHOR: Dmitry Eliseev * */ public final boolean update(final DBStatement query) { try { query.m_Statement.execute(); return true; } catch (final SQLException e) { LoggingUtility.error("Can't execute update query: " + query.m_Statement.toString()); } finally { closeStatement(query); } /* Update failed */ return false; } /* End of 'DBConnection::update' method */ /* * * METHOD: Executes prepared statement like COUNT != 0 query * RETURN: True if exists, False otherwise * PARAM: [IN] sql - prepared statement * AUTHOR: Dmitry Eliseev * */ public final boolean exists(final DBStatement query) { final AbstractList<Map<String, Object>> results = select(query); return results != null && results.size() != 0; } /* End of 'DBConnection::DBConnection' method */ /* * * METHOD: Executes prepared statement like SELECT query * RETURN: List of records (maps) if success, null otherwise * PARAM: [IN] sql - prepared statement * AUTHOR: Dmitry Eliseev * */ public final AbstractList<Map<String, Object>> select(final DBStatement query) { try { /* Container for result set */ final AbstractList<Map<String, Object>> results = new LinkedList<Map<String, Object>>(); /* Query execution */ query.m_Statement.execute(); /* Determine columns meta data */ final ResultSetMetaData metaData = query.m_Statement.getMetaData(); /* Obtain real data */ final ResultSet resultSet = query.m_Statement.getResultSet(); while (resultSet.next()) { final Map<String, Object> row = new HashMap<String, Object>(); /* Copying fetched data */ for (int columnID = 1; columnID <= metaData.getColumnCount(); columnID++) row.put(metaData.getColumnName(columnID), resultSet.getObject(columnID)); /* Add row to results */ results.add(row); } /* That's it */ return results; } catch (final SQLException e) { LoggingUtility.error("Can't execute select query: " + query.toString()); } finally { closeStatement(query); } /* Return empty result */ return null; } /* End of 'DBConnection::select' method */ } /* End of 'DBConnection' class */
DBController.javaã¯ã©ã¹ã«ã泚æãæãå¿ èŠããããŸãã
DBController.java
package com.gesoftware.venta.db; import com.gesoftware.venta.logging.LoggingUtility; import java.util.*; /** * DB controller class definition **/ public abstract class DBController<T> { /* Real DB connection */ protected final DBConnection m_Connection; /* * * METHOD: Class constructor * PARAM: [IN] connection - real DB connection * AUTHOR: Dmitry Eliseev * */ protected DBController(final DBConnection connection) { m_Connection = connection; LoggingUtility.core(getClass().getCanonicalName() + " controller initialized"); } /* End of 'DBController::DBController' method */ /* * * METHOD: Requests collection of T objects using select statement * RETURN: Collection of objects if success, empty collection otherwise * PARAM: [IN] selectStatement - prepared select statement * AUTHOR: Dmitry Eliseev * */ protected final Collection<T> getCollection(final DBConnection.DBStatement selectStatement) { if (selectStatement == null) return new LinkedList<T>(); final AbstractList<Map<String, Object>> objectsCollection = m_Connection.select(selectStatement); if ((objectsCollection == null)||(objectsCollection.size() == 0)) return new LinkedList<T>(); final Collection<T> parsedObjectsCollection = new ArrayList<T>(objectsCollection.size()); for (final Map<String, Object> object : objectsCollection) parsedObjectsCollection.add(parse(object)); return parsedObjectsCollection; } /* End of 'DBController::getCollection' method */ /* * * METHOD: Requests one T object using select statement * RETURN: Object if success, null otherwise * PARAM: [IN] selectStatement - prepared select statement * AUTHOR: Dmitry Eliseev * */ protected final T getObject(final DBConnection.DBStatement selectStatement) { if (selectStatement == null) return null; final AbstractList<Map<String, Object>> objectsCollection = m_Connection.select(selectStatement); if ((objectsCollection == null)||(objectsCollection.size() != 1)) return null; return parse(objectsCollection.get(0)); } /* End of 'DBController::getObject' method */ /* * * METHOD: Parses object's map representation to real T object * RETURN: T object if success, null otherwise * PARAM: [IN] objectMap - object map, obtained by selection from DB * AUTHOR: Dmitry Eliseev * */ protected abstract T parse(final Map<String, Object> objectMap); } /* End of 'DBController' class */
DBControllerã¯ã©ã¹ã¯ãç¹å®ã®ããŒãã«ã®ãªããžã§ã¯ããæäœããããã«èšèšãããŠããŸãã ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ã§ã¯ãããŒã¿ããŒã¹ããŒãã«ããšã«ã³ã³ãããŒã©ãŒãäœæãããŸãã ã³ã³ãããŒã©ã¬ãã«ã§ã¯ãããŒã¿ããŒã¹ã®ããŒã¿ãæ¿å ¥ãæœåºãæŽæ°ããããã®ã¡ãœãããå®è£ ãããŸãã
äžéšã®æäœã§ã¯ãè€æ°ã®ããŒãã«ã®ããŒã¿ãäžåºŠã«å€æŽããå¿ èŠããããŸãã ãã®ããã«ããããŒãžã£ãŒã¬ãã«ãäœæãããŸããã åãããŒãžã£ãŒã¯ããã¹ãŠã®ã³ã³ãããŒã©ãŒã«ã¢ã¯ã»ã¹ã§ããŸãã ãããŒãžã£ãŒã¬ãã«ã§ã¯ãããšãã°ããŠãŒã¶ãŒXãéšå±Aã«é 眮ããããªã©ã®é«ã¬ãã«ã®æäœãå®è£ ãããŸãã æ°ããã¬ãã«ã®æœè±¡åãžã®ç§»è¡ã«å ããŠããããŒãžã£ãŒã¯ããŒã¿ãã£ãã·ã³ã°ã¡ã«ããºã ãå®è£ ããŸãã ããšãã°ã誰ããèªèšŒãè©Šã¿ãããè©äŸ¡ãç¥ãããå Žåã¯ãããŒã¿ããŒã¹ã«ã¢ã¯ã»ã¹ããå¿ èŠã¯ãããŸããã ãŠãŒã¶ãŒãŸãã¯ãŠãŒã¶ãŒè©äŸ¡ãæ åœãããããŒãžã£ãŒããã®ããŒã¿ãä¿åããŸãã ãããã£ãŠãããŒã¿ããŒã¹ã®å šäœçãªè² è·ã軜æžãããŸãã
æœè±¡åã®æ¬¡ã®ã¬ãã«ã¯ãã³ãã©ãŒã§ãã 次ã®ã¯ã©ã¹ã¯ãIserverHandlerã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ãšããŠäœ¿çšãããŸãã
StickersHandler.java
package com.gesoftware.stickers.server.handlers; import com.gesoftware.stickers.model.common.Definitions; public final class StickersHandler implements IServerHandler { private final Map<Class, StickersQueryHandler> m_Handlers = new SynchronizedMap<Class, StickersQueryHandler>(); private final StickersManager m_Context; private final JobsManager m_JobsManager; public StickersHandler(final DBConnection connection) { m_Context = new StickersManager(connection); m_JobsManager = new JobsManager(Definitions.c_TasksThreadSleepTime); registerQueriesHandlers(); registerJobs(); } private void registerJobs() { m_JobsManager.addTask(new TaskGameUpdateStatus(m_Context)); m_JobsManager.addTask(new TaskGameUpdatePhase(m_Context)); } private void registerQueriesHandlers() { /* Menu handlers */ m_Handlers.put(QueryAuthorization.class, new QueryAuthorizationHandler(m_Context)); m_Handlers.put(QueryRegistration.class, new QueryRegistrationHandler(m_Context)); m_Handlers.put(QueryRating.class, new QueryRatingHandler(m_Context)); /* Logout */ m_Handlers.put(QueryLogout.class, new QueryLogoutHandler(m_Context)); /* Rooms handlers */ m_Handlers.put(QueryRoomRefreshList.class, new QueryRoomRefreshListHandler(m_Context)); m_Handlers.put(QueryRoomCreate.class, new QueryRoomCreateHandler(m_Context)); m_Handlers.put(QueryRoomSelect.class, new QueryRoomSelectHandler(m_Context)); m_Handlers.put(QueryRoomLeave.class, new QueryRoomLeaveHandler(m_Context)); /* Games handler */ m_Handlers.put(QueryGameLeave.class, new QueryGameLeaveHandler(m_Context)); m_Handlers.put(QueryGameIsStarted.class, new QueryGameIsStartedHandler(m_Context)); m_Handlers.put(QueryGameWhichPhase.class, new QueryGameWhichPhaseHandler(m_Context)); /* Question handler */ m_Handlers.put(QueryGameAsk.class, new QueryGameAskHandler(m_Context)); /* Answer handler */ m_Handlers.put(QueryGameAnswer.class, new QueryGameAnswerHandler(m_Context)); /* Voting handler */ m_Handlers.put(QueryGameVote.class, new QueryGameVoteHandler(m_Context)); /* Users handler */ m_Handlers.put(QueryUserHasInvites.class, new QueryUserHasInvitesHandler(m_Context)); m_Handlers.put(QueryUserAvailable.class, new QueryUserAvailableHandler(m_Context)); m_Handlers.put(QueryUserInvite.class, new QueryUserInviteHandler(m_Context)); } @SuppressWarnings("unchecked") private synchronized Serializable userQuery(final String clientID, final Object query) { final StickersQueryHandler handler = getHandler(query.getClass()); if (handler == null) { LoggingUtility.error("Handler is not registered for " + query.getClass()); return new ResponseCommonMessage("Internal server error: can't process: " + query.getClass()); } return handler.processQuery(m_Context.getClientsManager().getClient(clientID), query); } private StickersQueryHandler getHandler(final Class c) { return m_Handlers.get(c); } private ServerResponse answer(final Serializable object) { return new ServerResponse(new Message(object)); } @Override public boolean onConnect(final String clientID, final InetAddress clientAddress) { LoggingUtility.info("User <" + clientID + "> connected from " + clientAddress.getHostAddress()); m_Context.getClientsManager().clientConnected(clientID); return true; } @Override public final ServerResponse onReceive(final String clientID, final Message message) { final Object object = message.getObject(); if (object == null) { LoggingUtility.error("Unknown object accepted"); return answer(new ResponseCommonMessage("Internal server error: empty object")); } return new ServerResponse(new Message(userQuery(clientID, object))); } @Override public void onDisconnect(final String clientID) { m_Context.getClientsManager().clientDisconnected(clientID); LoggingUtility.info("User <" + clientID + "> disconnected"); } public void stop() { m_JobsManager.stop(); } }
ãã®ã¯ã©ã¹ã«ã¯ãèŠæ±ãªããžã§ã¯ãã®ã¯ã©ã¹ã®å¯Ÿå¿ãããã³ãã©ãŒãªããžã§ã¯ããžã®ãããã³ã°ãå«ãŸããŸãã ç§ã®æèŠã§ã¯ããã®ã¢ãããŒãã«ããïŒå®è¡æéã¯æéã§ã¯ãããŸãããïŒã³ãŒããé©åã«ç·šæã§ããŸãã åãã³ãã©ãŒã¯ããªã¯ãšã¹ãã«é¢é£ããç¹å®ã®ã¿ã¹ã¯ã1ã€ã ã解決ããŸãã ããšãã°ããŠãŒã¶ãŒç»é²ã
ãŠãŒã¶ãŒç»é²ããã»ããµãŒ
package com.gesoftware.stickers.server.handlers.registration; import com.gesoftware.stickers.model.enums.UserStatus; import com.gesoftware.stickers.model.objects.User; import com.gesoftware.stickers.model.queries.registration.QueryRegistration; import com.gesoftware.stickers.model.responses.registration.ResponseRegistrationInvalidEMail; import com.gesoftware.stickers.model.responses.registration.ResponseRegistrationFailed; import com.gesoftware.stickers.model.responses.registration.ResponseRegistrationSuccessfully; import com.gesoftware.stickers.model.responses.registration.ResponseUserAlreadyRegistered; import com.gesoftware.stickers.server.handlers.StickersQueryHandler; import com.gesoftware.stickers.server.managers.StickersManager; import com.gesoftware.venta.logging.LoggingUtility; import com.gesoftware.venta.utility.ValidationUtility; import java.io.Serializable; public final class QueryRegistrationHandler extends StickersQueryHandler<QueryRegistration> { public QueryRegistrationHandler(final StickersManager context) { super(context); } @Override public final Serializable process(final User user, final QueryRegistration query) { if (!ValidationUtility.isEMailValid(query.m_EMail)) return new ResponseRegistrationInvalidEMail(); if (m_Context.getUsersManager().isUserRegistered(query.m_EMail)) return new ResponseUserAlreadyRegistered(); if (!m_Context.getUsersManager().registerUser(query.m_EMail, query.m_PasswordHash, query.m_Name)) return new ResponseRegistrationFailed(); LoggingUtility.info("User <" + user.m_ClientID + "> registered as " + query.m_EMail); return new ResponseRegistrationSuccessfully(); } @Override public final UserStatus getStatus() { return UserStatus.NotLogged; } }
ã³ãŒãã¯éåžžã«èªã¿ãããã§ãããïŒ
ã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³
ã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã¯ããã³ãã©ãŒãšãŸã£ããåãããžãã¯ãå®è£ ããŸããããµãŒããŒã®å¿çã®ã¿ãå®è£ ããŸãã IClientHandlerã€ã³ã¿ãŒãã§ã€ã¹ããç¶æ¿ãããã¯ã©ã¹ã«å®è£ ãããŸãã
ç°ãªãã¢ã¯ãã£ããã£ã®æ°ã¯ãã²ãŒã ã®ç¶æ ã®æ°ãšåãã§ãã ãµãŒããŒãšã®å¯Ÿè©±ã®åçã¯éåžžã«ç°¡åã§ãã
- ãŠãŒã¶ãŒãäœããã®ã¢ã¯ã·ã§ã³ãå®è¡ããŸãïŒããšãã°ããã²ãŒã ãå ¥åããŠãã ããããã¿ã³ãã¯ãªãã¯ããŸãïŒ
- ã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã¯ãé²è¡ç¶æ³ãã€ã¢ãã°ããŠãŒã¶ãŒã«è¡šç€ºããŸãã
- ã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã¯ãŠãŒã¶ãŒè³æ Œæ å ±ããµãŒããŒã«éä¿¡ããŸã
- ãµãŒããŒã¯ãªã¯ãšã¹ããåŠçããã¬ã¹ãã³ã¹ãéãè¿ããŸã
- åçã«å¯Ÿå¿ãããã³ãã©ãŒã¯ãé²è¡ç¶æ³ãã€ã¢ãã°ãé衚瀺ã«ããŸã
- å¿çãåŠçãããçµæãã¯ã©ã€ã¢ã³ãã«åºåãããŸã
ãããã£ãŠãã¯ã©ã€ã¢ã³ããšãµãŒããŒã®äž¡æ¹ã®ããžãã¹ããžãã¯ã¯ãå€æ°ã®å°ããªæ§é åã¯ã©ã¹ã«åå²ãããŸãã
ãã1ã€ã話ããããã®ã¯ãã¢ããªå è³Œå ¥ã§ãã ããã§ããã€ãã®èšäºã§èŠãããã«ãã¢ããªå è³Œå ¥ã¯ã¢ããªã±ãŒã·ã§ã³ãåçåããããã®éåžžã«äŸ¿å©ãªãœãªã¥ãŒã·ã§ã³ã§ãã ç§ã¯ã¢ããã€ã¹ãããããšã«ããã¢ããªã±ãŒã·ã§ã³ã«åºåãè¿œå ãã$ 1ã§ç¡å¹ã«ããæ©èœãè¿œå ããŸããã
課éã®åŠçãå§ããã°ããã®é ãç§ã¯ãããGoogleã§ã©ã®ããã«æ©èœããããèããã®ã«èšå€§ãªæéãè²»ãããŸããã Googleãæ¯æãã«é¢ããæ å ±ïŒæ¯æãçªå·ãªã©ïŒãçºè¡ããã²ãŒã ãµãŒããŒã«è»¢éããããããæ¢ã«Google APIã«é£çµ¡ããŠç¢ºèªãå®äºããåŸãè«ççã«æããã®ã§ãé·ãéãµãŒããŒã§æ¯æããæ€èšŒããæ¹æ³ãç解ããããšããŸããæ¯æããã©ããã çµå±ã®ãšããããã®ãããªã¹ããŒã ã¯ãµãã¹ã¯ãªãã·ã§ã³ã«å¯ŸããŠã®ã¿æ©èœããŸãã éåžžã®è³Œå ¥ã§ã¯ããã¹ãŠãã¯ããã«ç°¡åã§ãã ã¢ããªã±ãŒã·ã§ã³ã§è³Œå ¥ãè¡ããšãGoogleã¯è³Œå ¥ãšãã®ã¹ããŒã¿ã¹ïŒãã§ãã¯ïŒããã³ãã®ãã§ãã¯ã®é»å眲åã«é¢ããæ å ±ãå«ãJSONãè¿ããŸãã ãããã£ãŠããã¹ãŠã¯ãGoogleãä¿¡é ŒããŠããŸããïŒããšãã質åã«ããã£ãŠããŸãã :)å®éããã®ãããªãã¢ãåä¿¡ããåŸãã²ãŒã ãµãŒããŒã«éä¿¡ãããŸããã²ãŒã ãµãŒããŒã¯ã次ã®2ã€ã®ããšã確èªããã ãã§æžã¿ãŸãã
- æ¢ã«ãã®ãããªãªã¯ãšã¹ãããµãŒããŒã«éä¿¡ããŸãããïŒããã¯ãã²ãŒã é貚ã®è³Œå ¥ãªã©ãGoogleã«ãã£ãŠå¶åŸ¡ãããŠããªãæäœã®ããã§ãïŒ
- å°åæã¯é»å眲åã§æ£ãã眲åãããŠããŸããïŒçµå±ãå ±éã®GoogleããŒã¯ãµãŒããŒãå«ããã¹ãŠã®äººã«ç¥ãããŠããŸãïŒ
ãã®ã¡ã¢ã§ã¯ãæåã®æ··firstãšãã話ãçµããããããšæããŸãã ç§ã¯èªåã®èšäºãäœåºŠãèªã¿ãŸããããããã¯æè¡çãªããã¹ãã®çæ³ã§ã¯ãªããããããç解ããã®ã¯é£ãããããããŸããããå°æ¥ïŒãããããªãïŒãç¶æ³ãä¿®æ£ããããšããŸãã
åç §è³æ
- ã¢ããªå 課éã®æŠèŠ
- Androidã¢ããªã§ã®ã¢ããªå è³Œå ¥ãŸãã¯å éšæ¯æã
- Androidã¢ããªã§ã®ã¢ããªå è³Œå ¥
ãµãŒãããŒãã£ã®ã©ã€ãã©ãª
ãããã«
誰ããæåŸãŸã§èªãå¿èãæã£ãŠããå Žåãç§ã¯ããã®äœå®¶ã®ãµããããŠããªãã®ã§ãæè¬ãè¡šããŸããããã§å ¬éããã®ã¯ãããåããŠãªã®ã§ã匷ãæ¹å€ããŠãã ããããã®åºçã®çç±ã®1ã€ã¯ããµãŒããŒã®è² è·ãã¹ããè¡ãå¿ èŠãããã ãã§ãªããã²ãŒã ã®èŠèŽè ãåéããå¿ èŠããããšèšããããhabraeffectãã§ãããšã©ãŒ/äžæ£ç¢ºãã®å åã«æè¬ããŸãããæž èŽããããšãããããŸããïŒ
çµè«ãšããŠãå°ããªã¢ã³ã±ãŒãïŒçŸæç¹ã§ã¯è¿œå ã§ããŸããïŒïŒå°æ¥å ¬éãã䟡å€ã¯ãããŸããïŒãããããªããã©ã®ãããã¯ã§åºçç©ãèå³ãæã¡ãŸããïŒ
- æ°åŠïŒç·åœ¢ä»£æ°
- æ°åŠïŒåæ
- æ°åŠïŒæ°å€ããã³æé©åã®æ¹æ³
- æ°åŠïŒé¢æ£æ°åŠãšã¢ã«ãŽãªãºã çè«
- æ°åŠïŒèšç®å¹ŸäœåŠ
- ããã°ã©ãã³ã°ïŒã³ã³ãã¥ãŒã¿ãŒã°ã©ãã£ãã¯ã¹ã®åºç€ïŒããšãã°ããã®ãããžã§ã¯ãïŒ
- ããã°ã©ãã³ã°ïŒã·ã§ãŒããŒããã°ã©ãã³ã°
- ããã°ã©ãã³ã°ïŒã²ãŒã éçº
- ç©çåŠïŒçžå¯Ÿæ§çè«
- ç©çåŠïŒå€©äœç©çåŠ
ã©ãïŒ