일단 wii용 에뮬은 돌리는데에 문제가 좀 많군요. 그래픽카드나 pc사양이 좋아야 할 듯.
그리고 오픈소스로 진행중이다보니 개발중인 버전을 받아서 테스트를 해볼 수 있습니다.
안정적인 버전이 현재 R4771인 듯 한데, 이 버전을 받아서 해보니 마리오카트 등 게임이 잘 안되더라구요. 그래서 누가 R5017버전 올렸길래 한번 받아서 해봤더니 마리오카트는 잘 되더라구요(물론 구동만 잘 되고, 느리게 돌아갑니다-_-)
난 wii도 있는데, 이짓을 해본거지-_- 난 정말 할일이 없는 사람인 듯......-_-

암튼 wii에뮬 홈페이지입니다. 여기서 다운로드할 수 있습니다.
http://www.dolphin-emu.com/downloads.php?cat_id=7

최근 개발버전은 svn에서 확인할 수 있어요. 구글코드로군요.
http://code.google.com/p/dolphin-emu/

iso파일은 불법이니 알아서들 구하세요~

1. wii용 리모콘이 인식 됨.
일단 wii용 컨트롤러로 pc에서 게임을 할 수 있습니다. wii용 리모트 컨트롤러는 블루투스 방식이기 때문에 해당 pc나 노트북이 블루투스를 지원을 하게 되면 컨트롤러로 추가할 수 있습니다. 추가하고, 게임 구동하고 컨트롤러에 빨간 버튼 누르니 인식하네요.
단, 그 바는 어디다가 연결할 수가 없는데, 그래서 모션같은 건 컨트롤 할 수 없네요. 어떤 분이 촛불을 세워놓으면 된다곤 했는데, 그렇게 까지 리모콘으로 하고 싶진 않......-_-

가상 WII 리모콘으로 처음에 설정이 되어있는데요. 이건 마우스가 리모콘이 되버립니다. 조작해보면 알겠지만, 편할 것 같지만 서도 엄청 불편합니다-_-

2. 안돌아가는 게임이 좀 있음
메탈슬러그를 가지고 있는데, 그냥 오프닝 영상에서 클릭해버리면 다운되더니 끝나네요-_-
wii뮤직은 잘 되는 것 같고...... 최근에 나온 동물의 숲은 컨트롤러가 안 먹히는군요.
돌핀 r4771(안정버전이라고 공식홈페이지에 올려놓은...-_-)버전에선 마리오 카트도 안되고, 뭐 다 안되더라구요. 나중에 막 깨져요.
사용자 삽입 이미지

마리오카트는 느리지만, 잘 작동됨.

사용자 삽입 이미지

A버튼 누르는 순간 다운-_-

사용자 삽입 이미지

컨트롤러가 안 먹힘-_- 그래픽도 다 안나오는 듯.


3. 최악의 속도
제 노트북은 2.66GHz듀얼코어, 4g램에 geforce 9300mgs인데, 조낸 느립니다. 일단 노트북이고 그래픽카드가 쪼끔 안 좋은데, 고사양에서는 어떨지는 모르겠네요. 사양이 좋으면 돌리는데에는 무난할 듯. 쿼드코어에 조낸 비싼 그래픽 카드 정도?(이 장비를 사느니 wii본체를 사는게 더 싸게 먹....)

4. 구운 시디를 직접 구동 가능
iso파일 뿐만 아니라 iso파일을 구운 시디에서 구동도 가능합니다. 물론 로딩시간이 좀 더 길어지네요.

5. 구동영상

뭐 아직은 멀었다고 말하고 싶네요. 그나저나 nintendo계열의 게임기가 뚫리기 가장 쉬운가봅니다. ps나 xbox는 그런거 안뜨는 것 같은데. 더 간단하고 그래서 그런가....
ps2에뮬도 있는데, 이것도 컴 사양이 엄청 좋아야지 할 수 있죠^^
wii 게임이 하고 싶으시다면 고생하지 마시고, wii하나 사세요-_-
 
Posted by 머드초보
,
 
앱엔진에 뭔가 제 사이트를 만들고 싶어서 이렇게 삽질을 하고 있는데, 망할 제한이 왜이렇게 많지-_-

암튼, "구글 앱 엔진"에서는 JPA를 지원합니다. 하지만, 이상하게도 잘 안됩니다-_- 굉장히 제한적으로 이것저것 막아둔 것 같습니다. 사실 구글 앱 엔진에서는 DataBase를 BigTable인지 뭐시기인지 그걸 사용하고, 직접적으로 접근을 못하기 때문에(전부 프로그래밍 또는 관리페이지(관리페이지도 매우 제한적인-_-)에서만 관리 가능), 이걸 이용하는 API에서도 엄청나게 뭔가 막아둔 것 같습니다.
뭐 좀 해보려고 하면 에러를 내뱉습니다. 검색해보면 구글앱엔진에서만 나는 에러입니다-_- 사실 아직 구글앱엔진이 프리뷰버전이기에 뭐라 따지지도 못하는 게 사실입니다^^ 정식버전(언제나오려나....Beta딱지 떼는데 10년넘게 걸리겠지-_-)나오면 매우 안정화가 되지 않을까 싶습니다^^

암튼, Spring3 + JPA의 조합으로 앱엔진에 올리는 건 성공했는데, 사실 스프링에서 제공하는 TransactionManager를 사용했어야 했는데, JPATemplate으로 뭔가 처리를 하면 잘 안되더군요-_- 일단 가져오고, persist하고, 이런건 잘 되는데, 왜 삭제가 안될까요-_- 삭제가 안되서 그냥JPATemplate빼고 했습니다-_-
JPATemplate사용해서 성공하신 분 트랙백좀 ㅠㅠ

0. 환경
Eclipse 3.5 + Google AppEngine Plugin + Spring 3.0.0
일단 스프링3다운로드 - http://www.springsource.org/download

1. 프로젝트 생성
New Project -> Google에 있는 Web Application Project 선택.
Project Name은 SosiSchedule. package는 com.mudchobo.
Use Google Web Toolkit은 체크해제. 사용안할꺼라....(이것도 언제한번 공부해야하는데-_-)
Finish.

2. 라이브러리 복사 및 build path추가
spring3에서는 spring.jar가 산산조각 났어요. 필요한 것만 넣으면 되는 듯.
일단 제가 사용한 것은....
org.springframework.asm-3.0.0.RELEASE.jar
org.springframework.beans-3.0.0.RELEASE.jar
org.springframework.context-3.0.0.RELEASE.jar
org.springframework.core-3.0.0.RELEASE.jar
org.springframework.expression-3.0.0.RELEASE.jar
org.springframework.orm-3.0.0.RELEASE.jar
org.springframework.web.servlet-3.0.0.RELEASE.jar
org.springframework.web-3.0.0.RELEASE.jar
그리고, jstl을 사용할 것이기에....
jstl.jar와 standard.jar
※이번버전에서는 lib폴더가 없습니다-_- 어디서 찾아야하는 거지-_- 암튼 그래서 2.5.6버전에서 가져왔습니다^^

앱엔진에서는 lib폴더 복사로 libpath가 잡히지 않네요. 그래서 각각 다 추가해줘야한다는...-_-
일단 war/WEB-INF/lib폴더에 복사 후에 복사한 파일 선택 후 오른쪽버튼 후, Build Path -> Add to Build Path 선택하면 됩니다^^

3. web.xml파일 수정
web.xml
[code]<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/sosischedule/*</url-pattern>
</servlet-mapping>

<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>[/code]
일단 sosischedule/*요청은 spring이 받습니다.

4. dispacher-servlet.xml파일과 persistence.xml파일 생성
war/WEB-INF/폴더에 생성
dispatcher-servlet.xml
[code]<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.mudchobo" />
   
    <bean id="entityManager"
        factory-bean="EMF"
        factory-method="get" />
   
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
</beans>[/code]

src/META-INF/ 폴더에 생성
persistence.xml
[code]<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
   
    <persistence-unit name="transactions-optional">
        <provider>org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider</provider>
        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>
        </properties>
    </persistence-unit>
</persistence>[/code]

5. EMF클래스 생성.
이제 jpa접근할 수 있는 EntityManagerFactory클래스(EMF)를 생성해봅시다.
com.mudchobo.sosi.sosischedule.dao.EMF.java
[code]package com.mudchobo.sosischedule.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.springframework.stereotype.Component;

@Component
public final class EMF {
     private static final EntityManagerFactory emfInstance =
        Persistence.createEntityManagerFactory("transactions-optional");

    private EMF() {}

    public EntityManager get() {
        return emfInstance.createEntityManager();
    }
}[/code]

6. Entity클래스 생성
일단 Sosi와 Schedule이라는 Entity를 생성할 건데요. 둘의 관계는 1:N관계입니다.
com.mudchobo.sosischedule.entity.Sosi.java
[code]package com.mudchobo.sosischedule.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import com.google.appengine.api.datastore.Key;

@Entity
public class Sosi implements Serializable {
    private static final long serialVersionUID = 5448408922872112420L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Key key;
   
    private String sosiName;
   
    @OneToMany(mappedBy="sosi", cascade=CascadeType.ALL)
    private List<Schedule> scheduleList = new ArrayList<Schedule>();

    public Key getKey() {
        return key;
    }

    public void setKey(Key key) {
        this.key = key;
    }

    public List<Schedule> getScheduleList() {
        return scheduleList;
    }

    public void setScheduleList(List<Schedule> scheduleList) {
        this.scheduleList = scheduleList;
    }

    public String getSosiName() {
        return sosiName;
    }

    public void setSosiName(String sosiName) {
        this.sosiName = sosiName;
    }

    public Sosi() {
       
    }
   
    public Sosi(Key key, String sosiName) {
        super();
        this.key = key;
        this.sosiName = sosiName;
    }
}[/code]
com.mudchobo.sosischedule.entity.Schedule.java
[code]package com.mudchobo.sosischedule.entity;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

@Entity
public class Schedule implements Serializable{
    private static final long serialVersionUID = -8676837674549793653L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key key;
   
    private String program;
   
    @ManyToOne(fetch=FetchType.LAZY)
    private Sosi sosi;
   
    public Sosi getSosi() {
        return sosi;
    }

    public void setSosi(Sosi sosi) {
        this.sosi = sosi;
    }

    public Key getKey() {
        return key;
    }

    public void setKey(Key key) {
        this.key = key;
    }
   
   
    public String getKeyString() {
        return KeyFactory.keyToString(key);
    }
   
    public String getProgram() {
        return program;
    }

    public void setProgram(String program) {
        this.program = program;
    }
   
    public Schedule() {
    }

    public Schedule(String program, Sosi sosi) {
        this.program = program;
        this.sosi = sosi;
    }
}[/code]
일단 App Engine용 JPA에서는 ID 타입이 Long이면 관계형태를 사용할 수 없더라구요. 그래서 앱엔진에서 제공하는 Key타입이 있는데, 이걸 이용해야합니다.

7. Dao만들기
com.mudchobo.sosisochedule.SosiDao.java
[code]package com.mudchobo.sosischedule.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.google.appengine.api.datastore.KeyFactory;
import com.mudchobo.sosischedule.entity.Schedule;
import com.mudchobo.sosischedule.entity.Sosi;

@Repository
public class SosiDao {
    private EntityManager em;
   
    @Autowired
    public void setEntityManager(EntityManager em) {
        this.em = em;
       
        // 소시데이터 추가
        addSosi(new Long(1), "효연");
        addSosi(new Long(2), "윤아");
        addSosi(new Long(3), "수영");
        addSosi(new Long(4), "유리");
        addSosi(new Long(5), "태연");
        addSosi(new Long(6), "제시카");
        addSosi(new Long(7), "티파니");
        addSosi(new Long(8), "써니");
        addSosi(new Long(9), "서현");
    }
   
    public void addSosi(Long id, String sosiName) {
        em.getTransaction().begin();
        em.persist(new Sosi(KeyFactory.createKey(Sosi.class.getSimpleName(), id), sosiName));
        em.getTransaction().commit();
    }
   
    @SuppressWarnings("unchecked")
    public List<Sosi> getSosiList() {
        return em.createQuery("select s from Sosi s").getResultList();
    }

    public Sosi getSosi(Long sosiId) {
        return em.find(Sosi.class, sosiId);
    }
   
    @SuppressWarnings("unchecked")
    public List<Schedule> getScheduleList(final Long sosiId) {
        Query q = em.createQuery("select s.scheduleList from Sosi s where s.key = :key");
        q.setParameter("key", KeyFactory.createKey(Sosi.class.getSimpleName(), sosiId));
        return (List<Schedule>) q.getSingleResult();
    }
   
    public void addSchedule(Long sosiId, String program) {
        em.getTransaction().begin();
        Sosi sosi = em.find(Sosi.class, sosiId);
        sosi.getScheduleList().add(new Schedule(program, sosi));
        em.getTransaction().commit();
    }
   
    public void deleteSchedule(String scheduleKey) {
        em.getTransaction().begin();
        Schedule schedule = em.find(Schedule.class, scheduleKey);
        em.remove(schedule);
        em.getTransaction().commit();
    }
}[/code]
EntityManager받을 때 디폴트로 데이터를 넣어줘야 합니다(아까 위에서 말했듯이 프로그래밍적으로만 테이블을 생성할 수 있어서 이런 형태로 데이터를 넣어줘야합니다ㅠㅠ)

일단 실행해보고 데이터가 잘 생성되었는지 보려면 아래와 같은 주소로 접속해보면 됩니다.
http://localhost:8888/_ah/admin
일단 보고 삭제까지는 되는데, 테이블 생성같은 건 안되더라구요. 그리고 여기서 보여지는데에는 한글이 깨지는데 나중에 출력해보면 잘 나오니 걱정마시길-_-
사용자 삽입 이미지
8. Service 클래스 생성
com.mudchobo.sosischedule.service.SosiService.java
[code]package com.mudchobo.sosischedule.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mudchobo.sosischedule.dao.SosiDao;
import com.mudchobo.sosischedule.entity.Schedule;
import com.mudchobo.sosischedule.entity.Sosi;

@Service
public class SosiService {
   
    @Autowired
    private SosiDao sosiDao;
   
    public List<Sosi> getSosiList()
    {
        return sosiDao.getSosiList();
    }
   
    public Sosi getSosi(Long sosiId) {
        return sosiDao.getSosi(sosiId);
    }
   
    public List<Schedule> getScheduleList(Long sosiId) {
        return sosiDao.getScheduleList(sosiId);
    }
   
    public void deleteSchedule(String scheduleKey) {
        sosiDao.deleteSchedule(scheduleKey);
    }

    public void addSchedule(Long sosiId, String program) {
        sosiDao.addSchedule(sosiId, program);
    }
}[/code]
Service에서 하는 역할은 뭐 없네요-_-

9. Controller생성
스프링3.0에서 새로 추가된 기능인 REST기능입니다.
com.mudchobo.sosischedule.controller.SosiController.java
[code]package com.mudchobo.sosischedule.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.mudchobo.sosischedule.entity.Schedule;
import com.mudchobo.sosischedule.entity.Sosi;
import com.mudchobo.sosischedule.service.SosiService;

@Controller
public class SosiController {
    private static String PREFIX = "/sosischedule";
   
    @Autowired
    private SosiService sosiService;
   
    @RequestMapping(value="/", method=RequestMethod.GET)
    public String index(Model model) {
        List<Sosi> sosiList = sosiService.getSosiList();
        model.addAttribute("sosiList", sosiList);
       
        return "index";
    }
   
    @RequestMapping(value="/schedule/{sosiId}", method=RequestMethod.GET)
    public String getSchedule(
            @PathVariable("sosiId") Long sosiId,
            Model model) {
        Sosi sosi = sosiService.getSosi(sosiId);
        List<Schedule> scheduleList = sosiService.getScheduleList(sosiId);
        model.addAttribute("scheduleList", scheduleList)
            .addAttribute("sosi", sosi);
       
        return "sosi";
    }
   
    @RequestMapping(value="/schedule/{sosiId}/add", method=RequestMethod.POST)
    public String addSchedule(
            @PathVariable("sosiId") Long sosiId,
            @RequestParam("program") String program,
            Model model
            ) {
        sosiService.addSchedule(sosiId, program);
       
        return "redirect:" + PREFIX + "/schedule/" + sosiId;
    }
   
    @RequestMapping(value="/schedule/{sosiId}/{scheduleKey}", method=RequestMethod.GET)
    public String removeSchedule(
            @PathVariable("sosiId") Long sosiId,
            @PathVariable("scheduleKey") String scheduleKey,
            Model model) {
        sosiService.deleteSchedule(scheduleKey);
       
        return "redirect:" + PREFIX + "/schedule/" + sosiId;
    }
}[/code]

10. View jsp파일 생성
소시 리스트를 보여주는 index파일 입니다.
war/WEB-INF/jsp/index.jsp
[code]<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>소녀시대 스케줄</title>
</head>
<body>
    <div>
        스케줄 확인하기
        <ul>
        <c:forEach var="sosi" items="${sosiList}">
            <li><a href="/sosischedule/schedule/${sosi.key.id}">${sosi.key.id}. ${sosi.sosiName}</a></li>
        </c:forEach>
        </ul>
    </div>
</body>
</html>[/code]

해당 소시의 스케줄을 보여주는 스케줄 파일입니다.
war/WEB-INF/jsp/sosi.jsp
[code]<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>소녀시대 스케줄</title>
</head>
<body>
    <div>
        스케줄 확인하기
        <ul>
        <c:forEach var="sosi" items="${sosiList}">
            <li><a href="/sosischedule/schedule/${sosi.key.id}">${sosi.key.id}. ${sosi.sosiName}</a></li>
        </c:forEach>
        </ul>
    </div>
</body>
</html>[/code]
리다이렉트를 위한 파일입니다. 기존 index.html파일 지우시고, index.jsp파일 생성
index.jsp
[code]<% response.sendRedirect("/sosischedule/"); %>[/code]

앱엔진에 올려보았습니다.
http://2.latest.mudchobosample.appspot.com/sosischedule/

잘 되는 것 같네요.
 
Posted by 머드초보
,
 
VMWare가 한건했네요-_-
저 같은 사용자를 위해 이런 것이 나와주다니 너무 고맙네요. VMWare에서도 OSX Snow Leopard를 거의 완벽하게 지원하게 만들어버렸습니다.
주 OS를 OSX를 사용하겠다는 사람들에게는 맥을 사거나 해킨토시를 이용해 설치하거나 하면 됩니다. 그리고, Windows는 vmware나 페럴러즈같은 가상머신으로 너무 잘 돌아가니 이렇게 설치를 하면 되는데, 주 OS가 Windows이고 가끔 아이폰개발을 위해 osx를 사용하고 싶은 사용자는 선택의 여지가 없었습니다-_- VMWare 6대 버전에서는 너무 느리게 돌아가고 제대로 지원이 안되었기 때문이죠.
하지만, VMWare7에서는 메인보드에서 가상화를 지원하면 아마 이걸 이용해서 속도개선을 한 듯 보여요.
이제 Windows에서 가상머신으로 vmware를 통해 osx snow leopard를 설치할 수 있습니다. 물론 공식적인 지원은 아닙니다. 근데, 속도는 정말 빠르군요. 일부러 노리고 만들었나-_-

사용자 삽입 이미지
업데이트도 잘됩니다. 그리고, 프로세서는 4.30ghz로 나오네요. 메모리는 2gb로 해야 부드럽게 잘 돌아가는 듯.
아....제 노트북 사양은 2.66GHz 듀얼, 4gb입니다. z36입니다. 설정시에는 메모리 2gb로 잡았죠.

설치 도움사이트.
OSX가상머신만들기 : http://blog.naver.com/baljern/140098696647
OSX설치하기: http://blog.naver.com/baljern/140098695323
OSX VMWare Tools 설치하기 : http://blog.naver.com/baljern/140098695308

여기서 해킨토시 h-sl106.iso 파일이 필요합니다. 알아서 구하셔야......-_-

그리고, 사운드와 그래픽이 조쿰 느린 것을 느끼게 되는데, 이건 드라이버를 설치해야합니다.
저 같은 경우 여기서 받은 드라이버를 설치하니 잘 되더라구요^^ 아래 요술램프 지니효과나 dock효과 등도 부드럽게 잘 나오더라구요. 사운드도 처음엔 안나왔는데 설치하니 잘 나옵니다.

http://vmsvga2.sourceforge.net/
Download VMsvga2 files 클릭 후, Video에는 Common용으로 받으면 되구, Audio오는 Snow Leopard랑 Leopard용이 구분해 있으니 알아서 받으시면 될 듯.

그리고, 잠자기 모드로 들어가는 것을 꺼줘야 합니다.
시스템 환경설정 -> 에너지 절약 메뉴에 있어요~ 거기서 그냥 둘 다 사용안함으로 해주시면 돼요.

아래는 구동영상을 한번 찍어봤어요.
캡쳐중이라서 그런지 조금 버벅이는 면이 있지만, 보시다시피 아이폰 개발하는데에는 전혀 지장을 주지 않을 정도로 부드럽습니다.

나도 아이폰개발해보자-_-
 
Posted by 머드초보
,
 
Netbeans에서도 Google App Engine플러그인을 설치해서 개발할 수 있습니다.
하지만, 구글에서 공식적으로 제공하는 플러그인이 아니라 누가 만든 것 같네요.

이곳에서 보고 설치 및 샘플을 실행할 수 있습니다.

아.....이건 상관없는 그림이지만, 그림을 보면 볼수록 왠지 슬퍼지는데요.
오늘 권순선님 미투데이에서 발견했습니다-_-
사용자 삽입 이미지

Java를 낳고 돌아가신 Sun이군요-_- 오라클이 인수하는 걸 EC에서 승인했다더군요.



암튼 대충 따라해보면...

1. 플러그인 설치
Tools -> Plugins -> Settings -> Add -> Name에 App Engine이라고 하고, URL에 아래 주소를 입력
그러면 Available Plugins에 5개의 Google App Engine플러그인이 생김. 체크해서 설치 고고싱

2. SDK다운로드
여기서 자바용으로 받아서 적당한 폴더에 풀어주면 됨 ㄷㄷ

3. Google App Engine 서버 설정
넷빈즈에서 Services탭에서 Servers에서 마우스 오른쪽버튼 클릭 후 Add Server선택
Google App Engine을 선택한 뒤, 위에서 받은 sdk폴더 경로 지정. 포트는 맘에 드는걸로 하면 끝남

4. 새로운 프로젝트 생성
New 프로젝트 -> Java Web -> Web Application -> Project Name은 HelloGoogleAppEngine -> Server는 Google App Engine -> Finish하면 끝남.
F6을 눌러서 실행하면 Hello World 볼 수 있음 ㄷㄷ

5. 배포
배포 시 Web Pages -> WEB-INF -> appengine-web.xml파일에서 Application Name을 자신이 얻은 Name으로 수정하고 해야함.

그런데 배포 시 약간 문제가 있음.
아무것도 안건드렸다고해도 이런 에러를 보게 될 꺼임.
[code]java.lang.IllegalStateException: cannot find javac executable based on java.home, tried "C:\Program Files\Java\jre6\bin\javac.exe" and "C:\Program Files\Java\bin\javac.exe"
Unable to update app: cannot find javac executable based on java.home, tried "C:\Program Files\Java\jre6\bin\javac.exe" and "C:\Program Files\Java\bin\javac.exe"
Please see the logs [C:\Users\mudchobo\AppData\Local\Temp\appcfg7950519452562723725.log] for further information.[/code]
javac파일을 java\bin에서 찾는 것 같음. 거기엔 javac.exe파일이 없음. java.home위치를 수정하는 법을 몰라서, 검색해보니 그냥 그 폴더에 javac.exe를 복사하는 거임. tools.jar파일도 lib폴더에 같이 복사해야함 ㄷㄷ

제꺼기준으로
C:\Program Files\Java\jdk1.6.0_17\bin\javac.exe파일을 -> C:\Program Files\Java\jre6\bin에 복사.
C:\Program Files\Java\jdk1.6.0_17\lib\tools.jar파일을 -> C:\Program Files\Java\jre6\lib\폴더에 복사.

그러면 잘 될꺼임.

ps. 결론은.......그냥 이클립스 플러그인 쓰는 게 나아요. 그건 GWT연동도 되거든요-_- 이런 짓을 하면서 까지 넷빈즈에서 개발하고 싶진 않은 듯. 공식으로 지원하는 플러그인으로....-_- 이클립스가 짱인 듯.
 
Posted by 머드초보
,
 
아주 오래전에 Hibernate xml로 삽질했던 기억이 있는데, Annotation으로 해보겠다는 게 세월(?)이 벌써 이렇게 흘렀군요.

하이버네이트는 셋팅이 참 어렵군요. 책을 보면 그냥 hibernate함수를 이용해서 어떻게 이용하는지, 하이버네이트의 특성이 주로 나와있는데, 셋팅에 대한 삽질은 좀 자세하지 않은 듯(내가 못본 것일 수도 있음-_-)

NetBeans 6.8에서 삽질했습니다.
넷빈즈다운로드 : http://netbeans.org/downloads/index.html

일단 소녀시대 테이블만 하나 만들어 놓읍시다.
테이블은 sosi랑 schedule 2개가 1:N의 관계형태로 만드려고 합니다. (DB쪽에 취약해서 맞는지 모르겠네-_- 뭐 다취약하지만-_-)
[code]
DROP TABLE IF EXISTS `sosi`;
CREATE TABLE IF NOT EXISTS `sosi` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `birthYear` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;

INSERT INTO `sosi` (`id`, `birthYear`, `name`) VALUES
(1, 1989, '효연'),
(2, 1990, '윤아'),
(3, 1990, '수영'),
(4, 1989, '유리'),
(5, 1989, '태연'),
(6, 1989, '제시카'),
(7, 1989, '티파니'),
(8, 1990, '써니'),
(9, 1991, '서현');
[/code]

1. 프로젝트 생성
File -> New Project(Ctrl + Shift + N) -> Java -> Java Application -> Project이름은 SosiSchedule

2. 하이버네이트 설정파일 셋팅
 Ctrl + N을 눌러서 새로운 파일을 만듭니다. SosiSchedule을 선택하고, Hibernate -> Hibernate Configuration Wizard선택, File Name은 hibernate.cfg 디폴트로, Database는 자신이 셋팅하고 sosi테이블을 만들어놓은 Mysql 데이터베이스를 선택합니다. 안만들었으면 New Database Connector를 선택해서 Host, Port, Database, User Name Password를 입력하면 됩니다. 이거 하면 자동으로 Library가 추가되나봅니다.
설정 파일이 만들어졌어요. 근데, 하이버네이트에서는 src최상위 폴더에 넣으면 자동으로 설정파일을 인식하나봐요. 설정파일 경로 지정하는 부분이 없는 것 같은데-_-
테이블 자동생성 및 날라가는 sql을 보기위해 아래 두옵션을 추가합니다.
[code]<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>[/code]

3. HibernateUtl만들기
Ctrl + N을 눌러서 새로운 파일 작성 -> Hibernate -> HibernateUtl.java, ClassName은 HibernateUtl로 package는 sosischedule.util로 finish!

4. 매핑할 ENTITY클래스 작성
일단 entity클래스는 database에 table이 존재하면 자동으로 만들 수 있습니다.
Ctrl + N을 눌러서 새로운 파일 작성 -> Persistence -> Entity Classes  from Database 선택.
Database Connection에서 셋팅한 mysql선택하면  테이블명이 나오는데, sosi테이블을 Add합니다.
package는 알아보기 쉽게 sosischedule.entity로 하고 finish를...-_-
이쁘게 소스가 만들어지네요.
Sosi.java
[code]/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sosischedule.entity;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 *
 * @author mudchobo
 */
@Entity
@Table(name = "sosi")
@NamedQueries({
    @NamedQuery(name = "Sosi.findAll", query = "SELECT s FROM Sosi s"),
    @NamedQuery(name = "Sosi.findById", query = "SELECT s FROM Sosi s WHERE s.id = :id"),
    @NamedQuery(name = "Sosi.findByBirthYear", query = "SELECT s FROM Sosi s WHERE s.birthYear = :birthYear"),
    @NamedQuery(name = "Sosi.findBySosiName", query = "SELECT s FROM Sosi s WHERE s.sosiName = :sosiName")})
public class Sosi implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Long id;
    @Basic(optional = false)
    @Column(name = "birthYear")
    private int birthYear;
    @Column(name = "sosiName")
    private String sosiName;

    public Sosi() {
    }

    public Sosi(Long id) {
        this.id = id;
    }

    public Sosi(Long id, int birthYear) {
        this.id = id;
        this.birthYear = birthYear;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public int getBirthYear() {
        return birthYear;
    }

    public void setBirthYear(int birthYear) {
        this.birthYear = birthYear;
    }

    public String getSosiName() {
        return sosiName;
    }

    public void setSosiName(String sosiName) {
        this.sosiName = sosiName;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof Sosi)) {
            return false;
        }
        Sosi other = (Sosi) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "sosischedule.entity.Sosi[id=" + id + "]";
    }

}
[/code]
각각의 어노테이션들은 구글링을 통해 찾아보는걸로 저도 잘 몰라서-_-
Annotation기반으로 하기전에는 mapping xml파일을 작성했는데, 그걸 그냥 클래스에 보기좋게 해놓은 거라고 보면 될 듯.

스케쥴 클래스는 직접 만들어봅시다.
Ctrl + N을 통해 새로운 파일생성, Persistence -> Entity Class, Class Name은 Schedule, package는 sosischedule.entity선택 후 finish.
그러면 id만 달랑 있습니다. 여기에 칼럼을 만들어 봅시다. 많이 만들면 귀찮아 지니까-_- program명과 소시객체 연동하는 것만 만들어봅시다.
[code]private String program;
private Sosi sosi;[/code]입력하고, Alt + Insert하면 getter, setter자동생성기로 만듭니다.
사실 이렇게만 만들어 놓아도 테이블이 생성됩니다-_- 다 디폴트로 만들어서. 귀찮으니까 이렇게만 만들고 맙시다-_- 아 그리고, 생성자를 두개 추가했습니다. 기본생성자와 property를 세팅해서 만들어주는 생성자.
그리고 테이블과 관계를 맺기 위해 @ManyToOne을 넣어줘야합니다. 안 넣어주면 무슨 Blob으로 그냥 저장해버리는..-_-
Schedule.java
[code]package sosischedule.entity;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Schedule implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String program;

    @ManyToOne
    private Sosi sosi;

    public Schedule() {
    }

    public Schedule(String program, Sosi sosi) {
        this.program = program;
        this.sosi = sosi;
    }

    public Sosi getSosi() {
        return sosi;
    }

    public void setSosi(Sosi sosi) {
        this.sosi = sosi;
    }

    public Long getId() {
        return id;
    }

    public String getProgram() {
        return program;
    }

    public void setProgram(String program) {
        this.program = program;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof Schedule)) {
            return false;
        }
        Schedule other = (Schedule) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "sosischedule.entity.Schedule[id=" + id + "]";
    }
}
[/code]
오...이저 hibernate.cfg.xml파일을 열어서 매핑파일이라고 추가합니다.
hibernate.cfg.xml
[code]<mapping class="sosischedule.entity.Sosi"/>
<mapping class="sosischedule.entity.Schedule"/>[/code]
작성한 클래스 두개. 이제 hql을 날릴 수 있어요. hibernate.cfg.xml파일을 선택 후 오른쪽버튼을 누르면 "Run HQL Query"라는 메뉴가 나와요.
from Sosi때리면 소시멤버데이터가 나오네요.
※여기서 해당 프로젝트에 대해서 한번이라도 run을 때리지 않으면 Sosi is not mapped라고 나오네요. 안되면 한번 실행하고 해보세요.
사용자 삽입 이미지
이제 다 된 것 같으니 dao와 service를 만들어봅시다.

5. Dao생성
sosischedule.dao.SosiScheduleDao.java파일을 생성
SosiScheduleDao.java
[code]package sosischedule.dao;

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import sosischedule.entity.Schedule;
import sosischedule.entity.Sosi;
import sosischedule.util.HibernateUtil;

public class SosiScheduleDao {

    public List<Sosi> getSosiList() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Query q = session.createQuery("from Sosi");
        List<Sosi> list = q.list();
        session.close();

        return list;
    }

    public Sosi getSosi(int sosiId) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Sosi sosi = (Sosi) session.get(Sosi.class, new Long(sosiId));
        session.close();

        return sosi;
    }

    public List<Schedule> getSchedule(Long sosiId) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Query q = session.createQuery("from Schedule s where s.sosi.id = " + sosiId);
        List<Schedule> list = q.list();
        session.close();

        return list;
    }

    public void addSchedule(Schedule schedule) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
        session.save(schedule);
        tx.commit();
        session.close();
    }

    public void removeSchedule(int scheduleId) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
        Schedule schedule =
                (Schedule) session.load(Schedule.class, new Long(scheduleId));
        session.delete(schedule);
        tx.commit();
        session.close();
    }
}
[/code]
음....분명 이렇게 하는 건 아닌 것 같아-_- 암튼, 일단 셋팅이 목적이니-_- 대충 이렇게도 할 수 있다는 것을..-_-
getSosiList는 소시리스트를 가져오고, getSosi는 소시를 가져오고, getSchedule은 스케쥴리스트를 가져오고, addSchedule은 스케쥴추가하고, removeSchedule은 스케쥴을 삭제하고...

6. 서비스생성
이걸 사용할 서비스를 만들어봅시다.
sosischedule.service.SosiScheduleService.java
[code]package sosischedule.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import sosischedule.dao.SosiScheduleDao;
import sosischedule.entity.Schedule;
import sosischedule.entity.Sosi;

public class SosiScheduleService {

    private SosiScheduleDao sosiScheduleDao = new SosiScheduleDao();

    public void menuSosi() {
        List<Sosi> sosiList = sosiScheduleDao.getSosiList();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while(true){
            try {
                for (Sosi sosi : sosiList) {
                    System.out.println(sosi.getId() + "." + sosi.getSosiName());
                }
                System.out.println("번호를 입력하세요!(0은 종료) => ");
                int menuNum = Integer.parseInt(br.readLine());
                if (menuNum == 0){
                    System.out.println("종료!");
                    break;
                }
                // 소시데이터 가져오기
                Sosi sosi = sosiScheduleDao.getSosi(menuNum);
                if (sosi != null){
                    menuSchedule(sosi);
                    break;
                } else {
                    System.out.println("없는 번호입니다.");
                }

            } catch (IOException ex) {
                Logger.getLogger(SosiScheduleService.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void menuSchedule(Sosi sosi) {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        while(true){
            try {
                List<Schedule> scheduleList = sosiScheduleDao.getSchedule(sosi.getId());
                for (Schedule schedule : scheduleList) {
                    System.out.println(schedule.getId() + "." + schedule.getProgram());
                }
                if (scheduleList.size() <= 0){
                    System.out.println("스케쥴이 없습니다.\n");
                }
                System.out.println("1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>");
                int menuNum = Integer.parseInt(br.readLine());
                if (menuNum == 0) {
                    System.out.println("뒤로!");
                    menuSosi();
                    break;
                }
                else if (menuNum == 1) {
                    System.out.println("스케쥴명 입력 : ");
                    String program = br.readLine();
                    System.out.println("스케쥴 = " + program);
                    sosiScheduleDao.addSchedule(new Schedule(program, sosi));
                    System.out.println("추가완료!");
                }
                else if (menuNum == 2) {
                    System.out.println("스케쥴번호 : ");
                    int scheduleId = Integer.parseInt(br.readLine());
                    sosiScheduleDao.removeSchedule(scheduleId);
                    System.out.println("삭제완료!");
                }
            } catch (IOException ex) {
                Logger.getLogger(SosiScheduleService.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}[/code]
메인에서 이렇게 사용하면 됩니다.
Main.java
[code]package sosischedule;

import sosischedule.service.SosiScheduleService;

public class Main {

    public static void main(String[] args) {
        SosiScheduleService sosiScheduleService = new SosiScheduleService();
        sosiScheduleService.menuSosi();
    }
}
[/code]

결과
[code]Hibernate: select sosi0_.id as id0_, sosi0_.birthYear as birthYear0_, sosi0_.sos
iName as sosiName0_ from sosi sosi0_
1.효연
2.윤아
3.수영
4.유리
5.태연
6.제시카
7.티파니
8.써니
9.서현
번호를 입력하세요!(0은 종료) =>
5
Hibernate: select sosi0_.id as id0_0_, sosi0_.birthYear as birthYear0_0_, sosi0_
.sosiName as sosiName0_0_ from sosi sosi0_ where sosi0_.id=?
Hibernate: select schedule0_.id as id1_, schedule0_.program as program1_, schedu
le0_.sosi_id as sosi3_1_ from Schedule schedule0_ where schedule0_.sosi_id=5
스케쥴이 없습니다.

1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>
1
스케쥴명 입력 :
태연의 친한친구
스케쥴 = 태연의 친한친구
Hibernate: insert into Schedule (program, sosi_id) values (?, ?)
추가완료!
Hibernate: select schedule0_.id as id1_, schedule0_.program as program1_, schedu
le0_.sosi_id as sosi3_1_ from Schedule schedule0_ where schedule0_.sosi_id=5
Hibernate: select sosi0_.id as id0_0_, sosi0_.birthYear as birthYear0_0_, sosi0_
.sosiName as sosiName0_0_ from sosi sosi0_ where sosi0_.id=?
3.태연의 친한친구
1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>
1
스케쥴명 입력 :
태연의 친한친구2
스케쥴 = 태연의 친한친구2
Hibernate: insert into Schedule (program, sosi_id) values (?, ?)
추가완료!
Hibernate: select schedule0_.id as id1_, schedule0_.program as program1_, schedu
le0_.sosi_id as sosi3_1_ from Schedule schedule0_ where schedule0_.sosi_id=5
Hibernate: select sosi0_.id as id0_0_, sosi0_.birthYear as birthYear0_0_, sosi0_
.sosiName as sosiName0_0_ from sosi sosi0_ where sosi0_.id=?
3.태연의 친한친구
4.태연의 친한친구2
1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>
2
스케쥴번호 :
4
Hibernate: select schedule0_.id as id1_1_, schedule0_.program as program1_1_, sc
hedule0_.sosi_id as sosi3_1_1_, sosi1_.id as id0_0_, sosi1_.birthYear as birthYe
ar0_0_, sosi1_.sosiName as sosiName0_0_ from Schedule schedule0_ left outer join
 sosi sosi1_ on schedule0_.sosi_id=sosi1_.id where schedule0_.id=?
Hibernate: delete from Schedule where id=?
삭제완료!
Hibernate: select schedule0_.id as id1_, schedule0_.program as program1_, schedu
le0_.sosi_id as sosi3_1_ from Schedule schedule0_ where schedule0_.sosi_id=5
Hibernate: select sosi0_.id as id0_0_, sosi0_.birthYear as birthYear0_0_, sosi0_
.sosiName as sosiName0_0_ from sosi sosi0_ where sosi0_.id=?
3.태연의 친한친구
1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>[/code]
와....잘된다....-_-
 
Posted by 머드초보
,